深入PHP面向对象、模式与实践——对象工具(3)
2017-03-27 21:44
771 查看
反射API
反射API由一系列可以分析属性、方法和类的内置类组成。入门
反射API不仅仅被用于检查类。例如,ReflectionFunction类提供了关于给定函数的信息,ReflectionExtension类可以查看编译到PHP语言中的扩展。利用反射API的这些类,可以在运行时访问对象、函数和脚本中的扩展的信息。反射的另一用途是根据命名规则创建一个调用模板类中方法的框架。
开始行动
ReflectionClass提供揭示给定类所有信息的方法,无论这个类是用户定义的还是PHP自带的内置类。
$prod_class = new ReflectionClass('CdProduct'); Reflection::export($prod_class);
该函数与调试函数var_dump()相比较,var_dump()函数是汇总数据的通用工具,但使用前必须先实例化一个对象,而且无法提供想Reflection::export()提供的那么多细节。
$cd = new CdProduct("cd1", "bob", "bobbleson", 4, 50); var_dump($cd);
var_dump()和它的姊妹函数print_r()是检测PHP代码中数据的利器,但对于类和函数,反射API提供了更高层次的功能。
检查类
接着,让我们使用ReflectionClass对象来研究脚本中的CDProduct。这个类属于哪一种类型?可以创建实例吗?下面这个函数回答了这些问题:
function classData(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->isAbstract()) { $details .= "$name is an abstract class\n"; } if ($class->isInterface()) { $details .= "$name is interface\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"; } return $details; } $prod_class = new ReflectionClass(('CdProduct')); print classData($prod_class);
你甚至可以检查用户自定义的相关源代码。ReflectionClass对象提供自定义类所在的文件名及文件中类的起始和终止行。
class ReflectionUtil { static function getClassSource(ReflectionClass $class) { $path = $class->getFileName(); $lines = @file($path); $from = $class->getStartLine(); $to = $class->getEndLine(); $len = $to - $from + 1; return implode(array_slice($lines, $from - 1, $len)); } } print ReflectionUtil::getClassSource(new ReflectionClass('CdProduct'));
在实际项目中,应该检查参数和代码结果。
检查方法
$prod_class = new ReflectionClass('CdProduct'); $methods = $prod_class->getMethods(); foreach ($methods as $method) { print methodData($method); print "\n----\n"; } 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 an abstract class\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; }
可以像之前那样使用ReflectionClass那样获得类方法的源代码。
class ReflectionUtil { static function getMethodSou e90e rce(ReflectionMethod $method) { $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 = new ReflectionClass('CdProduct'); $method = $class->getMethod('getSummaryLine'); print ReflectionUtil::getMethodSource($method);
检查方法参数
在PHP5中,声明类方法时可以限制参数中对象的类型,因此检查方法的参数变得非常必要。为此,反射API提供了ReflectionParameter类。
$class = new ReflectionClass('CdProduct'); $method = $class->getMethod('__construct'); $params = $method->getParameters(); foreach ($params as $param) { print argData($param) . "\n"; } 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"; } return $details; }
使用反射API
假设我们要创建一个类来动态调用Module对象,即该类可以自由加载第三方插件并集成进已有的系统,而不需把第三方代码硬编码进原有的代码。要达到这个目的,可以在module接口或抽象类中定义一个execute()方法,强制要求所有的子类必须实现该方法。可以允许用户在外部XML配置文件中列出所有Module类。系统可以使用XML提供的信息来加载一定数目的Module对象,然后对每个Module对象调用execute()。
class Person { public $name; function __construct($name) { $this->name = $name; } } interface Module { function execute(); } class FtpModule implements Module { function setHost($host) { print "FtpModule::setHost():$host\n"; } function setUser($user) { print "FtpModule::setUser():$user\n"; } function execute() { } } class PersonModule implements Module { function setPerson(Person $person) { print "PersonModule::setPerson():{$person->name}\n"; } function execute() { } } class ModuleRunner { private $configData = array( "PersonModule" => array('person' => 'bob'), "FtpModule" => array('host' => 'example.com', 'user' => 'anon') ); private $modules = array(); function init() { $interface = new ReflectionClass('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); // } array_push($this->modules, $module); } } 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面向对象、模式与实践——对象工具(2)
- 深入PHP面向对象、模式与实践——设计模式
- 深入php面向对象、模式与实践
- 深入PHP面向对象、模式与实践——对象
- 深入PHP面向对象、模式与实践——高级特性(2)
- php面向对象书籍推荐:深入PHP:面向对象、模式与实践(第3版)
- 深入PHP面向对象、模式与实践——高级特性(4)
- 深入PHP面向对象、模式与实践——生成对象(1)
- 深入PHP面向对象、模式与实践——生成对象(3)
- 深入PHP面向对象、模式与实践——让面向对象编程更加灵活的模式(3)
- 深入PHP面向对象、模式与实践——对象与设计
- 深入PHP面向对象、模式与实践——企业模式(3)
- 深入php面向对象、模式与实践
- 深入PHP面向对象、模式与实践
- 深入PHP面向对象、模式与实践(第 2 版) 高清PDF版下载
- 深入PHP面向对象、模式与实践——执行及描述任务(1)
- 深入PHP面向对象、模式与实践——执行及描述任务(2)
- 深入PHP面向对象、模式与实践——模式原则(1)
- 深入PHP面向对象、模式与实践——执行及描述任务(5)
- 深入PHP面向对象、模式与实践——高级特性(6)