function reflectMethod($class, $method) { $methodInfo = new ReflectionMethod($class, $method); echo "**********************************\n"; echo "Reflecting on method {$class}::{$method}()\n\n"; echo "__toString():\n"; var_dump($methodInfo->__toString()); echo "\nexport():\n"; var_dump(ReflectionMethod::export($class, $method, true)); echo "\n**********************************\n"; }
/** * Exports a reflection method object. * * Returns the output if TRUE is specified for $return, printing it otherwise. * This is purely a wrapper method, which calls the corresponding method of * the parent class (ReflectionMethod::export()). * @param string|object $class * Name or instance of the class declaring the method * @param string $name * Name of the method * @param boolean $return * Whether to return (TRUE) or print (FALSE) the output * @return mixed */ public static function export($class, $name, $return = false) { return parent::export($class, $name, $return); }
/** * Method to trigger an event listener priority * * @param string $name * @param array $args * @throws Exception * @return void */ public function trigger($name, array $args = array()) { if (isset($this->listeners[$name])) { if (!isset($this->results[$name])) { $this->results[$name] = array(); } foreach ($this->listeners[$name] as $action) { if (end($this->results[$name]) == self::STOP) { return; } $args['result'] = end($this->results[$name]); $realArgs = array(); $params = array(); // Get and arrange the argument values in the correct order // If the action is a closure object if ($action instanceof \Closure) { $refFunc = new \ReflectionFunction($action); foreach ($refFunc->getParameters() as $key => $refParameter) { $params[] = $refParameter->getName(); } // Else, if the action is a callable class/method combination } else { if (is_string($action) || is_callable($action, false, $callable_name)) { // If the callable action is a string, parse the class/method from it if (is_string($action)) { // If a static call if (strpos($action, '::')) { $ary = explode('::', $action); $cls = $ary[0]; $mthd = $ary[1]; // If an instance call } else { if (strpos($action, '->')) { $ary = explode('->', $action); $cls = $ary[0]; $mthd = $ary[1]; $action = array(new $cls(), $mthd); // Else, if a new/construct call } else { $action = str_replace('new ', null, $action); $cls = $action; $mthd = '__construct'; } } } else { $cls = substr($callable_name, 0, strpos($callable_name, ':')); $mthd = substr($callable_name, strrpos($callable_name, ':') + 1); } $methodExport = \ReflectionMethod::export($cls, $mthd, true); // Get the method parameters if (stripos($methodExport, 'Parameter') !== false) { $matches = array(); preg_match_all('/Parameter \\#(.*)\\]/m', $methodExport, $matches); if (isset($matches[0][0])) { foreach ($matches[0] as $param) { // Get name $argName = substr($param, strpos($param, '$')); $argName = trim(substr($argName, 0, strpos($argName, ' '))); $params[] = str_replace('$', '', $argName); } } } } else { throw new Exception('Error: The action must be callable, i.e. a closure or class/method combination.'); } } foreach ($params as $value) { $realArgs[$value] = $args[$value]; } // If the method is the constructor, create object if (isset($mthd) && $mthd == '__construct') { $reflect = new \ReflectionClass($action); $result = $reflect->newInstanceArgs($realArgs); $this->results[$name][] = $result; // Else, just call it } else { $result = call_user_func_array($action, $realArgs); $this->results[$name][] = $result; } if ($result == self::KILL) { $this->alive = false; } } } }
/** * Tests export. */ public function testToString() { $tests = array('lines', 'docComment', 'noComment', 'prototype', 'noPrototype', 'parameters', 'reference', 'noReference', 'noClosure', 'noNamespace', 'userDefined', 'shadow'); foreach ($tests as $test) { $rfl = $this->getMethodReflection($test); $this->assertSame($rfl->internal->__toString(), $rfl->token->__toString()); $this->assertSame(InternalReflectionMethod::export($this->getClassName($test), $test, true), ReflectionMethod::export($this->getBroker(), $this->getClassName($test), $test, true)); $rfl = $this->getMethodReflection($test, true); $this->assertSame($rfl->internal->__toString(), $rfl->token->__toString()); $this->assertSame(InternalReflectionMethod::export($this->getClassName($test), $test, true), ReflectionMethod::export($this->getBroker(), $this->getClassName($test), $test, true)); } $tests = array('constructorDestructor' => array('__construct', '__destruct'), 'clone' => array('__clone', 'noClone'), 'declaringClass' => array('parent', 'child', 'parentOverlay'), 'invoke' => array('publicInvoke', 'protectedInvoke'), 'accessLevel' => array('privateExtended', 'privateNoExtended', 'protectedExtended', 'protectedNoExtended'), 'modifiers' => array('publicAbstract', 'publicFinal', 'publicStatic', 'publicNoStatic', 'protectedAbstract', 'protectedFinal', 'protectedStatic', 'protectedNoStatic', 'privateFinal', 'privateStatic', 'privateNoStatic')); foreach ($tests as $class => $classTests) { $rfl = $this->getClassReflection($class); $rfl_fromString = $this->getClassReflection($class, true); foreach ($classTests as $method) { // @todo inherits not supported yet $this->assertSame(preg_replace('~, inherits [\\w]+~', '', $rfl->internal->getMethod($method)->__toString()), $rfl->token->getMethod($method)->__toString()); $this->assertSame(preg_replace('~, inherits [\\w]+~', '', InternalReflectionMethod::export($this->getClassName($class), $method, true)), ReflectionMethod::export($this->getBroker(), $this->getClassName($class), $method, true)); $this->assertSame(preg_replace('~, inherits [\\w]+~', '', $rfl_fromString->internal->getMethod($method)->__toString()), $rfl_fromString->token->getMethod($method)->__toString()); } } $this->assertSame(InternalReflectionMethod::export('ReflectionMethod', 'isFinal', true), ReflectionMethod::export($this->getBroker(), 'ReflectionMethod', 'isFinal', true)); $this->assertSame(InternalReflectionMethod::export(new InternalReflectionMethod('ReflectionMethod', 'isFinal'), 'isFinal', true), ReflectionMethod::export($this->getBroker(), new InternalReflectionMethod('ReflectionMethod', 'isFinal'), 'isFinal', true)); }
$magic = array("__wakeup", "__destruct", "__toString", "__get", "__set", "__call"); foreach ($classlist as $class) { $reflClass = new ReflectionClass($class); // Ignore classes from PHP core/extensions if ($reflClass->isUserDefined()) { foreach ($magic as $method) { try { if ($reflClass->getMethod($method)) { $reflMethod = new ReflectionMethod($class, $method); $parent = $reflMethod->getDeclaringClass()->getName(); $filename = $reflMethod->getDeclaringClass()->getFileName(); $startline = $reflMethod->getStartLine(); // If filename is not defined the class inherits from a core/extension class if ($filename) { // Get the source code of the method $exp = $reflMethod->export($class, $method, 1); // Extract the filename, start and end line numbers preg_match("/@@\\s(.*)\\s(\\d+)\\s-\\s(\\d+)/i", $exp, $matches); $source = file($filename); // -1/+1 to include the first and last lines, incase code is on same line as method declaration $functionBody = implode("", array_slice($source, $matches[2] - 1, $matches[3] - $matches[2] + 1)); // Check for interesting function calls if (preg_match("/eval|assert|call_user_func|system|popen|shell_exec|include|require|file_get_contents|unlink|exec/", $functionBody, $m)) { $interesting = $m[0]; } print $class . "::" . $method . "() "; if ($parent !== $class) { print "[extends " . $parent . "] "; } if (isset($interesting)) { print "{calls " . $interesting . "} ";
/** * 获取方法注释 * @param unknown $methodName * @return multitype: */ public static function getMethodAnnotation($methodName) { $export = \ReflectionMethod::export(__CLASS__, $methodName, 1); $export = explode('Method [ ', $export); return "\t" . $export[0]; }
/** * Get methods * * @return void */ protected function getClassMethods() { // Detect and set methods $methods = $this->getMethods(); if (count($methods) > 0) { foreach ($methods as $value) { $methodExport = \ReflectionMethod::export($value->class, $value->name, true); // Get the method docblock if (strpos($methodExport, '/*') !== false && strpos($methodExport, '*/') !== false) { $docBlock = substr($methodExport, strpos($methodExport, '/*')); $docBlock = substr($docBlock, 0, strpos($methodExport, '*/') + 2); } else { $docBlock = null; } $method = $this->getMethod($value->name); $visibility = 'public'; if ($method->isPublic()) { $visibility = 'public'; } else { if ($method->isProtected()) { $visibility = 'protected'; } else { if ($method->isPrivate()) { $visibility = 'private'; } } } $mthd = new Generator\MethodGenerator($value->name, $visibility, $method->isStatic()); if (null !== $docBlock && strpos($docBlock, '/*') !== false) { $mthd->setDocblock(Generator\DocblockGenerator::parse($docBlock, $mthd->getIndent())); } $mthd->setFinal($method->isFinal())->setAbstract($method->isAbstract()); // Get the method parameters if (stripos($methodExport, 'Parameter') !== false) { $matches = array(); preg_match_all('/Parameter \\#(.*)\\]/m', $methodExport, $matches); if (isset($matches[0][0])) { foreach ($matches[0] as $param) { $name = null; $value = null; $type = null; // Get name $name = substr($param, strpos($param, '$')); $name = trim(substr($name, 0, strpos($name, ' '))); // Get value if (strpos($param, '=') !== false) { $value = trim(substr($param, strpos($param, '=') + 1)); $value = trim(substr($value, 0, strpos($value, ' '))); $value = str_replace('NULL', 'null', $value); } // Get type $type = substr($param, strpos($param, '>') + 1); $type = trim(substr($type, 0, strpos($type, '$'))); if ($type == '') { $type = null; } $mthd->addArgument($name, $value, $type); } } } // Get method body if (strpos($methodExport, '@@') !== false && file_exists($this->getFilename())) { $lineNums = substr($methodExport, strpos($methodExport, '@@ ') + 3); $start = trim(substr($lineNums, strpos($lineNums, ' '))); $end = substr($start, strpos($start, ' - ') + 3); $start = substr($start, 0, strpos($start, ' ')); $end = (int) $end; if (is_numeric($start) && is_numeric($end)) { $classLines = file($this->getFilename()); $body = null; $start = $start + 1; $end = $end - 1; for ($i = $start; $i < $end; $i++) { if (isset($classLines[$i])) { if (substr($classLines[$i], 0, 8) == ' ') { $body .= substr($classLines[$i], 8); } else { if (substr($classLines[$i], 0, 4) == ' ') { $body .= substr($classLines[$i], 4); } else { if (substr($classLines[$i], 0, 2) == "\t\t") { $body .= substr($classLines[$i], 2); } else { if (substr($classLines[$i], 0, 1) == "\t") { $body .= substr($classLines[$i], 1); } else { $body .= $classLines[$i]; } } } } } } $mthd->setBody(rtrim($body), false); } } $this->generator->code()->addMethod($mthd); } } }
public function testExport() { self::assertEquals(ReflectionMethod::export('TestMethods', 'm1', true), ezcReflectionMethod::export('TestMethods', 'm1', true)); self::assertEquals(ReflectionMethod::export('TestMethods', 'm2', true), ezcReflectionMethod::export('TestMethods', 'm2', true)); self::assertEquals(ReflectionMethod::export('TestMethods', 'm3', true), ezcReflectionMethod::export('TestMethods', 'm3', true)); self::assertEquals(ReflectionMethod::export('TestMethods', 'm4', true), ezcReflectionMethod::export('TestMethods', 'm4', true)); self::assertEquals(ReflectionMethod::export(new TestMethods(), 'm1', true), ezcReflectionMethod::export(new TestMethods(), 'm1', true)); self::assertEquals(ReflectionMethod::export(new TestMethods(), 'm2', true), ezcReflectionMethod::export(new TestMethods(), 'm2', true)); self::assertEquals(ReflectionMethod::export(new TestMethods(), 'm3', true), ezcReflectionMethod::export(new TestMethods(), 'm3', true)); self::assertEquals(ReflectionMethod::export(new TestMethods(), 'm4', true), ezcReflectionMethod::export(new TestMethods(), 'm4', true)); }
<?php class Foo { public $prop; function Func($name) { echo "Hello {$name}"; } } ReflectionClass::export('Foo'); //output: Class [ class Foo ] { @@ /home/cg/root/main.php 3-10 - Constants [0] { } - Static properties [0] { } - Static methods [0] { } - Properties [1] { Property [ public $prop ] } - Methods [1] { Method [ public method Func ] { @@ /home/cg/root/main.php 7 - 9 - Parameters [1] { Parameter #0 [ $name ] } } } } ReflectionObject::export(new Foo()); // output: Object of class [ class Foo ] { @@ /home/cg/root/main.php 3-10 - Constants [0] { } - Static properties [0] { } - Static methods [0] { } - Properties [1] { Property [ public $prop ] } - Dynamic properties [0] { } - Methods [1] { Method [ public method Func ] { @@ /home/cg/root/main.php 7 - 9 - Parameters [1] { Parameter #0 [ $name ] } } } } ReflectionMethod::export('Foo', 'func'); // output: Method [ public method Func ] { @@ /home/cg/root/main.php 7 - 9 - Parameters [1] { Parameter #0 [ $name ] } } ReflectionProperty::export('Foo', 'prop'); //output: Property [ public $prop ] ReflectionExtension::export('standard'); //output: Extension [ extension #15 standard version 5.5.18 ] ...