Skip to content

Instantly share code, notes, and snippets.

@crusj
Last active August 27, 2019 01:42
Show Gist options
  • Save crusj/9bd67c0e5d4be93a7ca88cdf7e636c84 to your computer and use it in GitHub Desktop.
Save crusj/9bd67c0e5d4be93a7ca88cdf7e636c84 to your computer and use it in GitHub Desktop.
利用phpdoc以及反射实现对象工厂
<?php
/**
* author jianglong
* date 2019/8/13 上午9:10
*/
/**
* Class AbstractFactory
*
* @author jianglong
*/
abstract class AbstractFactory
{
/**
* @var array $instances
*/
protected static $instances = [];
/**
* @var array $methods
*/
protected static $methods = [];
/**
*
* @param $name
* @param $param
* @return mixed
* @throws \ReflectionException
* @author jianglong
*/
public static function __callStatic($name, $param)
{
//没有默认参数,默认为重新生成对象
if (empty($param)) {
$param[0] = true;
}
$ref = new \ReflectionClass(static::class);
$namespace = $ref->getNamespaceName();
if (isset(self::$instances[$namespace][$name]) && self::$instances[$namespace][$name] != null && $param[0] === false) {
return self::$instances[$namespace][$name];
}
if (empty(self::$methods[$namespace])) {
static::parseDocMethod($ref->getDocComment(), $namespace);
}
foreach (self::$methods[$namespace] as $method) {
if ($name == $method['name']) {
$type = $method['type'];
if (strpos($method['type'], '\\') === false) {
$type = $ref->getNamespaceName() . '\\' . $type;
}
$class = new \ReflectionClass($type);
if ($class->isInstantiable()) {
static::$instances[$namespace][$name] = $class->newInstance();
return static::$instances[$namespace][$name];
} else {
throw new \Exception(sprintf("class %s can not instance", $method['type']));
}
}
}
throw new \Exception(sprintf("method %s can not found", $name));
}
private static function parseDocMethod(string $doc, string $namespace)
{
$find = '@method';
$docs = explode(PHP_EOL, $doc);
foreach ($docs as $line) {
$position = strpos($line, $find);
if ($position !== false) {
$method = substr($line, $position + strlen($find));
$methodPieces = preg_replace('/\n{2,}/', '\n', trim($method));
$methodPieces = preg_replace('/\(.*\)/', '', $methodPieces);
$methodPieces = explode(' ', $methodPieces);
if (count($methodPieces) < 2) {
continue;
}
static::$methods[$namespace][] = [
'type' => trim($methodPieces[0]),
'name' => trim($methodPieces[1]),
];
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment