深入PHP 面向对象、模式与实践 第5章 对象工具


深入PHP 面向对象、模式与实践 第5章 对象工具


正文

本章包括以下内容:

  • 包(package):将代码按逻辑分类打包
  • 命名空间:从PHP5.3开始,可以将代码元素封装在独立的单元中
  • 包含路径:为你的类库代码设置访问路径
  • 类函数和对象函数:测试对象、类、属性和方法的函数
  • 反射API(ReflectionAPI):一组强大的内置类,可以在代码运行时访问类信息

反射API

反射API的部分类:

  • Reflection 为类的摘要信息提供静态函数export()
  • ReflectionClass 类信息和工具
  • ReflectionMethod 类方法信息和工具
  • ReflectionParameter 方法参数信息
  • ReflectionProperty 类属性信息
  • ReflectionFunction 函数信息和工具
  • ReflectionExtension PHP拓展信息
  • ReflectionException 错误类
$prodclass = new \ReflectionClass('CdProduct');
\Reflection::export($prodclass);

获取源码的类:

class ReflectionUtil
{
    // 获取类源码
    public static function getClassSource(\ReflectionClass $class): string
    {
        $path  = $class->getFileName();
        $lines = @file($path);
        $from  = $class->getStartLine();
        $to    = $class->getEndLine();
        $len   = $to - $from + 1;
        return implode(array_slice($lines, $from - 1, $len));
    }

    // 获取方法源码
    public static function getMethodSource(\ReflectionMethod $method): string
    {
        $path  = $method->getFileName();
        $lines = @file($path);
        $from  = $method->getStartLine();
        $to    = $method->getEndLine();
        $len   = $to - $from + 1;
        return implode(array_slice($lines, $from - 1, $len));
    }
}

获取类详情信息的类:

class ClassInfo
{
    // 获取类详情
    public static function getData(\ReflectionClass $class)
    {
        $details = "";
        $name = $class->getName();
        if ($class->isUserDefined()) {
            $details .= "$name is user defined\n";
        }
        if ($class->isInternal()) {
            $details .= "$name is built-in\n";
        }
        if ($class->isInterface()) {
            $details .= "$name is interface\n";
        }
        if ($class->isAbstract()) {
            $details .= "$name is an abstract class\n";
        }
        if ($class->isFinal()) {
            $details .= "$name is a final class\n";
        }
        if ($class->isInstantiable()) {
            $details .= "$name can be instantiated\n";
        } else {
            $details .= "$name can not be instantiated\n";
        }

        if ($class->isCloneable()) {
            $details .= "$name can be cloned\n";
        } else {
            $details .= "$name can not be cloned\n";
        }
        return $details;
    }

    // 获取方法详情
    public static function methodData(\ReflectionMethod $method)
    {
        $details = "";
        $name = $method->getName();
        if ($method->isUserDefined()) {
            $details .= "$name is user defined\n";
        }
        if ($method->isInternal()) {
            $details .= "$name is built-in\n";
        }
        if ($method->isAbstract()) {
            $details .= "$name is abstract\n";
        }
        if ($method->isPublic()) {
            $details .= "$name is public\n";
        }
        if ($method->isProtected()) {
            $details .= "$name is protected\n";
        }
        if ($method->isPrivate()) {
            $details .= "$name is private\n";
        }
        if ($method->isStatic()) {
            $details .= "$name is static\n";
        }
        if ($method->isFinal()) {
            $details .= "$name is final\n";
        }
        if ($method->isConstructor()) {
            $details .= "$name is the constructor\n";
        }
        if ($method->returnsReference()) {
            $details .= "$name returns a reference (as opposed to a value)\n";
        }
        return $details;
    }

    // 获取参数详情
    public function argData(\ReflectionParameter $arg)
    {
        $details = "";
        $declaringclass = $arg->getDeclaringClass();
        $name  = $arg->getName();
        $class = $arg->getClass();
        $position = $arg->getPosition();
        $details .= "\$$name has position $position\n";
        if (! empty($class)) {
            $classname = $class->getName();
            $details .= "\$$name must be a $classname object\n";
        }
      
        if ($arg->isPassedByReference()) {
            $details .= "\$$name is passed by reference\n";
        }

        if ($arg->isDefaultValueAvailable()) {
            $def = $arg->getDefaultValue();
            $details .= "\$$name has default: $def\n";
        }

        if ($arg->allowsNull()) {
            $details .= "\$$name can be null\n";
        }

        return $details;
    }
}

实操:

$prodclass = new \ReflectionClass('CdProduct');
print ClassInfo::getData($prodclass);

$methods = $prodclass->getMethods();
foreach ($methods as $method) {
    print ClassInfo::methodData($method);
    print "\n----\n";
}

$method = $prodclass->getMethod("__construct");
$params = $method->getParameters();
foreach ($params as $param) {
    print ClassInfo::argData($param) . "\n";
}

实践类:

class ModuleRunner
{
    private $configData = [
        "popp\\ch05\\batch08\\PersonModule" => ['person' => 'bob'],
        "popp\\ch05\\batch08\\FtpModule"    => [
            'host' => 'example.com',
            'user' => 'anon'
        ]
    ];

    private $modules = [];

    // class ModuleRunner
    public function init()
    {
        $interface = new \ReflectionClass('popp\\ch05\\batch08\\Module');
        foreach ($this->configData as $modulename => $params) {
            $module_class = new \ReflectionClass($modulename);
            if (! $module_class->isSubclassOf($interface)) {
                throw new Exception("unknown module type: $modulename");
            }
            $module = $module_class->newInstance();
            foreach ($module_class->getMethods() as $method) {
                $this->handleMethod($module, $method, $params);
                // we cover handleMethod() in a future listing!
            }
            array_push($this->modules, $module);
        }
    }
    
    // class ModuleRunner
    public function handleMethod(Module $module, \ReflectionMethod $method, $params)
    {
        $name = $method->getName();
        $args = $method->getParameters();

        if (count($args) != 1 || substr($name, 0, 3) != "set" ) {
            return false;
        }

        $property = strtolower(substr($name, 3));

        if (! isset($params[$property])) {
            return false;
        }

        $arg_class = $args[0]->getClass();

        if (empty($arg_class)) {
            $method->invoke($module, $params[$property]);
        } else {
            $method->invoke(
                $module,
                $arg_class->newInstance($params[$property])
            );
        }
    }
}






参考资料

《深入PHP 面向对象、模式与实践(第3版)》 https://ibaiyang.github.io/blog/books/深入PHP面向对象模式与实践.pdf


返回