/** * @return self */ public static function from($from) : self { if (is_string($from) && strpos($from, '::')) { $from = new \ReflectionMethod($from); } elseif (is_array($from)) { $from = new \ReflectionMethod($from[0], $from[1]); } elseif (!$from instanceof \ReflectionFunctionAbstract) { $from = new \ReflectionFunction($from); } $method = new static(); $method->name = $from->isClosure() ? NULL : $from->getName(); foreach ($from->getParameters() as $param) { $method->parameters[$param->getName()] = Parameter::from($param); } if ($from instanceof \ReflectionMethod) { $method->static = $from->isStatic(); $method->visibility = $from->isPrivate() ? 'private' : ($from->isProtected() ? 'protected' : NULL); $method->final = $from->isFinal(); $method->abstract = $from->isAbstract() && !$from->getDeclaringClass()->isInterface(); $method->body = $from->isAbstract() ? FALSE : ''; } $method->returnReference = $from->returnsReference(); $method->variadic = PHP_VERSION_ID >= 50600 && $from->isVariadic(); $method->comment = $from->getDocComment() ? preg_replace('#^\\s*\\* ?#m', '', trim($from->getDocComment(), "/* \r\n\t")) : NULL; if (PHP_VERSION_ID >= 70000 && $from->hasReturnType()) { $returnType = $from->getReturnType(); $method->returnType = $returnType->isBuiltin() ? (string) $returnType : '\\' . $returnType; } return $method; }
/** * @return IAnnotationReflection */ public function getAnnotationReflection() { if ($this->annotationReflection === null) { $this->annotationReflection = AnnotationReflection::build($this->reflectionFunction->getDocComment()); } return $this->annotationReflection; }
public function testParse() { $fn = function ($param1 = true, $param2 = 'bho') { // function body }; $reflector = new \ReflectionFunction($fn); $comment = $reflector->getDocComment(); $parser = new DocBlockParser($comment); $this->assertEquals('Anonymous function description splitted in two lines', $parser->getDescription()); $this->assertFalse($parser->hasParam('param4')); $this->assertTrue($parser->hasParam('param1')); $param1 = $parser->getParam('param1'); $this->assertEquals('param1', $param1['name']); $this->assertEquals('bool', $param1['type']); $this->assertEquals('parameter1 description', $param1['description']); $this->assertEquals('parameter1 description', $parser->getParamDescription('param1')); $this->assertEquals('', $parser->getParamDescription('param4')); $params = $parser->getParams(); $this->assertTrue(is_array($params)); $this->assertEquals(3, count($params)); $this->assertEquals('param1', $params['param1']['name']); $this->assertEquals('bool', $params['param1']['type']); $this->assertEquals('parameter1 description', $params['param1']['description']); $this->assertEquals('param3', $params['param3']['name']); $this->assertEquals('string', $params['param3']['type']); $this->assertEquals('', $params['param3']['description']); }
/** * Show page documenting all routes available in this app. * * @param \Silex\Application $app * * @return \Symfony\Component\HttpFoundation\Response */ public function routesAction(\Silex\Application $app) { /** * @var \Symfony\Component\Routing\RouteCollection $routes */ $routes = $app['routes']; $routes = self::pullRoutesFromCollection($routes); $docs = array(); foreach ($routes as $route) { /** * @var \Silex\Route $route */ $controller = $route->getDefault('_controller'); $docKey = $route->getPattern(); if (is_array($controller)) { $method = new \ReflectionMethod($controller[0], $controller[1]); } elseif ($controller instanceof \Closure) { $method = new \ReflectionFunction($controller); } else { $docs[$docKey] = ''; continue; } $docs[$docKey] = self::parseSummaryFromDocComment($method->getDocComment()); } $bootstrap = $_SERVER['SCRIPT_FILENAME']; return $app['twig']->render('list-routes.html.twig', array('routes' => $routes, 'docs' => $docs, 'bootstrap' => $bootstrap)); }
/** * Returns the doc comment for this function * * @return string Doc comment for this function * @since PHP 5.1.0 */ public function getDocComment() { if ($this->reflectionSource instanceof ReflectionFunction) { return $this->reflectionSource->getDocComment(); } else { return parent::getDocComment(); } }
function update_script_selection_form() { $form = array(); $count = 0; $form['start'] = array('#tree' => TRUE, '#type' => 'fieldset', '#collapsed' => TRUE, '#collapsible' => TRUE); // Ensure system.module's updates appear first $form['start']['system'] = array(); $modules = drupal_get_installed_schema_version(NULL, FALSE, TRUE); foreach ($modules as $module => $schema_version) { $pending = array(); $updates = drupal_get_schema_versions($module); // Skip incompatible module updates completely, otherwise test schema versions. if (!update_check_incompatibility($module) && $updates !== FALSE && $schema_version >= 0) { // module_invoke returns NULL for nonexisting hooks, so if no updates // are removed, it will == 0. $last_removed = module_invoke($module, 'update_last_removed'); if ($schema_version < $last_removed) { $form['start'][$module] = array('#title' => $module, '#item' => '<em>' . $module . '</em> module can not be updated. Its schema version is ' . $schema_version . '. Updates up to and including ' . $last_removed . ' have been removed in this release. In order to update <em>' . $module . '</em> module, you will first <a href="http://drupal.org/upgrade">need to upgrade</a> to the last version in which these updates were available.', '#prefix' => '<div class="warning">', '#suffix' => '</div>'); continue; } $updates = drupal_map_assoc($updates); foreach (array_keys($updates) as $update) { if ($update > $schema_version) { // The description for an update comes from its Doxygen. $func = new ReflectionFunction($module . '_update_' . $update); $description = str_replace(array("\n", '*', '/'), '', $func->getDocComment()); $pending[] = "{$update} - {$description}"; if (!isset($default)) { $default = $update; } } } if (!empty($pending)) { if (!isset($default)) { $default = $schema_version; } $form['start'][$module] = array('#type' => 'hidden', '#value' => $default); $form['start'][$module . '_updates'] = array('#markup' => theme('item_list', $pending, $module . ' module')); } } unset($default); $count = $count + count($pending); } if (empty($count)) { drupal_set_message(t('No pending updates.')); unset($form); $form['links'] = array('#markup' => theme('item_list', update_helpful_links())); } else { $form['help'] = array('#markup' => '<p>The version of Drupal you are updating from has been automatically detected.</p>', '#weight' => -5); $form['start']['#title'] = strtr('!num pending updates', array('!num' => $count)); $form['has_js'] = array('#type' => 'hidden', '#default_value' => FALSE); $form['submit'] = array('#type' => 'submit', '#value' => 'Apply pending updates'); } return $form; }
/** * Test a function or method for a given class * * @dataProvider dataReflectionTestFunctions * * @param string|array $function The function name, or array of class name and method name. */ public function testFunction($function) { // We can't pass Reflector objects in here because they get printed out as the // data set when a test fails if (is_array($function)) { $ref = new \ReflectionMethod($function[0], $function[1]); $name = $function[0] . '::' . $function[1] . '()'; } else { $ref = new \ReflectionFunction($function); $name = $function . '()'; } $docblock = new \phpDocumentor\Reflection\DocBlock($ref); $doc_comment = $ref->getDocComment(); $method_params = $ref->getParameters(); $doc_params = $docblock->getTagsByName('param'); $this->assertNotFalse($doc_comment, sprintf('The docblock for `%s` should not be missing.', $name)); $this->assertNotEmpty($docblock->getShortDescription(), sprintf('The docblock description for `%s` should not be empty.', $name)); $this->assertSame(count($method_params), count($doc_params), sprintf('The number of @param docs for `%s` should match its number of parameters.', $name)); // @TODO check description ends in full stop foreach ($method_params as $i => $param) { $param_doc = $doc_params[$i]; $description = $param_doc->getDescription(); $content = $param_doc->getContent(); // @TODO decide how to handle variadic functions // ReflectionParameter::isVariadic — Checks if the parameter is variadic $is_hash = 0 === strpos($description, '{') && strlen($description) - 1 === strrpos($description, '}'); if ($is_hash) { $lines = explode("\n", $description); $description = $lines[1]; } $this->assertNotEmpty($description, sprintf('The @param description for the `%s` parameter of `%s` should not be empty.', $param_doc->getVariableName(), $name)); list($param_doc_type, $param_doc_name) = preg_split('#\\s+#', $param_doc->getContent()); $this->assertSame('$' . $param->getName(), $param_doc_name, sprintf('The @param name for the `%s` parameter of `%s` is incorrect.', '$' . $param->getName(), $name)); if ($param->isArray()) { $this->assertNotFalse(strpos($param_doc_type, 'array'), sprintf('The @param type hint for the `%s` parameter of `%s` should state that it accepts an array.', $param_doc->getVariableName(), $name)); } if (($param_class = $param->getClass()) && 'stdClass' !== $param_class->getName()) { $this->assertNotFalse(strpos($param_doc_type, $param_class->getName()), sprintf('The @param type hint for the `%s` parameter of `%s` should state that it accepts an object of type `%s`.', $param_doc->getVariableName(), $name, $param_class->getName())); } $this->assertFalse(strpos($param_doc_type, 'callback'), sprintf('`callback` is not a valid type. `callable` should be used in the @param type hint for the `%s` parameter of `%s` instead.', $param_doc->getVariableName(), $name)); if ($param->isCallable()) { $this->assertNotFalse(strpos($param_doc_type, 'callable'), sprintf('The @param type hint for the `%s` parameter of `%s` should state that it accepts a callable.', $param_doc->getVariableName(), $name)); } if ($param->isOptional()) { $this->assertNotFalse(strpos($description, 'Optional.'), sprintf('The @param description for the optional `%s` parameter of `%s` should state that it is optional.', $param_doc->getVariableName(), $name)); } else { $this->assertFalse(strpos($description, 'Optional.'), sprintf('The @param description for the required `%s` parameter of `%s` should not state that it is optional.', $param_doc->getVariableName(), $name)); } if ($param->isDefaultValueAvailable() && array() !== $param->getDefaultValue()) { $this->assertNotFalse(strpos($description, 'Default '), sprintf('The @param description for the `%s` parameter of `%s` should state its default value.', $param_doc->getVariableName(), $name)); } else { $this->assertFalse(strpos($description, 'Default '), sprintf('The @param description for the `%s` parameter of `%s` should not state a default value.', $param_doc->getVariableName(), $name)); } } }
public static function docBlock($function) { if (preg_match('/^(.*)::(.*)$/', $function, $matches)) { $reflection = new \ReflectionMethod($matches[1], $matches[2]); } elseif (preg_match('/([A-Z]+[\\w\\-\\d]+)$/', $function, $matches)) { $reflection = new \ReflectionClass('\\' . $function); } else { $reflection = new \ReflectionFunction($function); } return "<h3>{$function}</h3><br>" . preg_replace('/\\n/', ' <br>', $reflection->getDocComment()); }
/** * @param callable $code */ public function buildFromCode($code) { $this->assertCallable($code); $this->setCode($code); $reflector = new \ReflectionFunction($code); $parser = new DocBlockParser($reflector->getDocComment()); $this->setDescription($parser->getDescription()); foreach ($reflector->getParameters() as $parameter) { $description = $parser->getParamDescription($parameter->getName()); $this->addParameter($parameter, $description); } }
protected function setupFunction($function) { if (is_array($function)) { $ref = new \ReflectionMethod($function[0], $function[1]); $this->function_name = $function[0] . '::' . $function[1] . '()'; } else { $ref = new \ReflectionFunction($function); $this->function_name = $function . '()'; } $this->docblock = new \phpDocumentor\Reflection\DocBlock($ref); $this->doc_comment = $ref->getDocComment(); $this->method_params = $ref->getParameters(); $this->doc_params = $this->docblock->getTagsByName('param'); }
/** * Fetches all the annotations for a given suite and test block. * * @note repeated names are sorted with deepest first * * @param Spec\TestSuite $suite * @param Closure $cb * @return array */ protected function getAnnotations(Spec\TestSuite $suite, $cb) { $anns = array(); // Get annotations from the callback function first $reflFn = new \ReflectionFunction($cb); $docblock = $reflFn->getDocComment(); if (preg_match_all('/@(?P<name>[A-Za-z_-]+)(?:[ \\t]+(?P<value>.*?))?(\\*\\/|$)/m', $docblock, $matches)) { $numMatches = count($matches[0]); for ($i = 0; $i < $numMatches; ++$i) { $anns[$matches['name'][$i]][] = trim($matches['value'][$i]); } } // Fetch annotations from parent suites (deepest first) do { $anns = array_merge_recursive($anns, $suite->getAnnotations()); } while ($suite = $suite->getParent()); return $anns; }
public static function fromReflection(\ReflectionFunction $ref) { $function = new static(); if (false === ($pos = strrpos($ref->name, '\\'))) { $function->setName(substr($ref->name, $pos + 1)); $function->setNamespace(substr($ref->name, $pos)); } else { $function->setName($ref->name); } $function->referenceReturned = $ref->returnsReference(); $function->docblock = ReflectionUtils::getUnindentedDocComment($ref->getDocComment()); foreach ($ref->getParameters() as $refParam) { assert($refParam instanceof \ReflectionParameter); $param = PhpParameter::fromReflection($refParam); $function->addParameter($param); } return $function; }
/** * DocCommentを取得する * * @param mixed $object * @return string */ public static function getDocCommentRaw($object) { if ($object instanceof ReflectionMethod || $object instanceof ReflectionClass || $object instanceof ReflectionFunction || $object instanceof Injection\Spec) { return $object->getDocComment(); } // オブジェクトを判定 if (is_callable($object) && is_array($object)) { $rs = new ReflectionMethod($object[0], $object[1]); return $rs->getDocComment(); } if ($object instanceof Closure) { $rs = new ReflectionFunction($object); return $rs->getDocComment(); } if (is_array($object) && is_callable($object[count($object) - 1])) { return self::getDocCommentRaw($object[count($object) - 1]); } if (is_object($object)) { $rs = new ReflectionClass($object); return $rs->getDocComment(); } throw new Exception\CantRetriveDocComment($object); }
/** * Introspect a php callable and its phpdoc block and extract information about its signature * * @param callable $callable * @param string $plainFuncName * @return array|false */ protected function introspectFunction($callable, $plainFuncName) { // start to introspect PHP code if (is_array($callable)) { $func = new \ReflectionMethod($callable[0], $callable[1]); if ($func->isPrivate()) { error_log('XML-RPC: ' . __METHOD__ . ': method to be wrapped is private: ' . $plainFuncName); return false; } if ($func->isProtected()) { error_log('XML-RPC: ' . __METHOD__ . ': method to be wrapped is protected: ' . $plainFuncName); return false; } if ($func->isConstructor()) { error_log('XML-RPC: ' . __METHOD__ . ': method to be wrapped is the constructor: ' . $plainFuncName); return false; } if ($func->isDestructor()) { error_log('XML-RPC: ' . __METHOD__ . ': method to be wrapped is the destructor: ' . $plainFuncName); return false; } if ($func->isAbstract()) { error_log('XML-RPC: ' . __METHOD__ . ': method to be wrapped is abstract: ' . $plainFuncName); return false; } /// @todo add more checks for static vs. nonstatic? } else { $func = new \ReflectionFunction($callable); } if ($func->isInternal()) { // Note: from PHP 5.1.0 onward, we will possibly be able to use invokeargs // instead of getparameters to fully reflect internal php functions ? error_log('XML-RPC: ' . __METHOD__ . ': function to be wrapped is internal: ' . $plainFuncName); return false; } // retrieve parameter names, types and description from javadoc comments // function description $desc = ''; // type of return val: by default 'any' $returns = Value::$xmlrpcValue; // desc of return val $returnsDocs = ''; // type + name of function parameters $paramDocs = array(); $docs = $func->getDocComment(); if ($docs != '') { $docs = explode("\n", $docs); $i = 0; foreach ($docs as $doc) { $doc = trim($doc, " \r\t/*"); if (strlen($doc) && strpos($doc, '@') !== 0 && !$i) { if ($desc) { $desc .= "\n"; } $desc .= $doc; } elseif (strpos($doc, '@param') === 0) { // syntax: @param type $name [desc] if (preg_match('/@param\\s+(\\S+)\\s+(\\$\\S+)\\s*(.+)?/', $doc, $matches)) { $name = strtolower(trim($matches[2])); //$paramDocs[$name]['name'] = trim($matches[2]); $paramDocs[$name]['doc'] = isset($matches[3]) ? $matches[3] : ''; $paramDocs[$name]['type'] = $matches[1]; } $i++; } elseif (strpos($doc, '@return') === 0) { // syntax: @return type [desc] if (preg_match('/@return\\s+(\\S+)(\\s+.+)?/', $doc, $matches)) { $returns = $matches[1]; if (isset($matches[2])) { $returnsDocs = trim($matches[2]); } } } } } // execute introspection of actual function prototype $params = array(); $i = 0; foreach ($func->getParameters() as $paramObj) { $params[$i] = array(); $params[$i]['name'] = '$' . $paramObj->getName(); $params[$i]['isoptional'] = $paramObj->isOptional(); $i++; } return array('desc' => $desc, 'docs' => $docs, 'params' => $params, 'paramDocs' => $paramDocs, 'returns' => $returns, 'returnsDocs' => $returnsDocs); }
/** * Logs a call to a deprecated function. * The log message will be taken from the annotation. * @return void */ public static function logDeprecatedFunction() { if (!$GLOBALS['TYPO3_CONF_VARS']['SYS']['enableDeprecationLog']) { return; } // This require_once is needed for deprecation calls // thrown early during bootstrap, if the autoloader is // not instantiated yet. This can happen for example if // ext_localconf triggers a deprecation. require_once 'utility/class.t3lib_utility_debug.php'; $trail = debug_backtrace(); if ($trail[1]['type']) { $function = new ReflectionMethod($trail[1]['class'], $trail[1]['function']); } else { $function = new ReflectionFunction($trail[1]['function']); } $msg = ''; if (preg_match('/@deprecated\\s+(.*)/', $function->getDocComment(), $match)) { $msg = $match[1]; } // trigger PHP error with a short message: <function> is deprecated (called from <source>, defined in <source>) $errorMsg = 'Function ' . $trail[1]['function']; if ($trail[1]['class']) { $errorMsg .= ' of class ' . $trail[1]['class']; } $errorMsg .= ' is deprecated (called from ' . $trail[1]['file'] . '#' . $trail[1]['line'] . ', defined in ' . $function->getFileName() . '#' . $function->getStartLine() . ')'; // write a longer message to the deprecation log: <function> <annotion> - <trace> (<source>) $logMsg = $trail[1]['class'] . $trail[1]['type'] . $trail[1]['function']; $logMsg .= '() - ' . $msg . ' - ' . t3lib_utility_Debug::debugTrail(); $logMsg .= ' (' . substr($function->getFileName(), strlen(PATH_site)) . '#' . $function->getStartLine() . ')'; self::deprecationLog($logMsg); }
/** * Returns a list of all the pending updates. * * @return array[] * An associative array keyed by module name which contains all information * about database updates that need to be run, and any updates that are not * going to proceed due to missing requirements. * * The subarray for each module can contain the following keys: * - start: The starting update that is to be processed. If this does not * exist then do not process any updates for this module as there are * other requirements that need to be resolved. * - pending: An array of all the pending updates for the module including * the description from source code comment for each update function. * This array is keyed by the update name. */ public function getPendingUpdateInformation() { $functions = $this->getPendingUpdateFunctions(); $ret = []; foreach ($functions as $function) { list($module, $update) = explode("_{$this->updateType}_", $function); // The description for an update comes from its Doxygen. $func = new \ReflectionFunction($function); $description = trim(str_replace(array("\n", '*', '/'), '', $func->getDocComment()), ' '); $ret[$module]['pending'][$update] = $description; if (!isset($ret[$module]['start'])) { $ret[$module]['start'] = $update; } } return $ret; }
/** * cfdump-style debugging output * @param $var The variable to output. * @param $limit Maximum recursion depth for arrays (default 0 = all) * @param $label text to display in complex data type header * @param $depth Current depth (default 0) */ public function dump(&$var, $limit = 0, $label = '', $depth = 0) { if (!is_int($depth)) $depth = 0; if (!is_int($limit)) $limit = 0; if (($limit > 0) && ($depth >= $limit)) return; static $seen = array(); $he = function ($s) { return htmlentities($s); }; $tabs = "\n" . str_repeat("\t", $depth); $depth++; $printCount = 0; $self = $this; $echoFunction = function($var, $tabs, $limit = 0, $label = '', $depth = 0) use ($self) { if (!is_subclass_of($var, 'ReflectionFunctionAbstract')) { $var = new \ReflectionFunction($var); } echo "$tabs<table class=\"dump function depth${depth}\">$tabs<thead><tr><th>" . ($label != '' ? $label . ' - ' : '') . (is_callable(array($var, 'getModifiers')) ? htmlentities(implode(' ', \Reflection::getModifierNames($var->getModifiers()))) : '') . " function " . htmlentities($var->getName()) . "</th></tr></thead>$tabs<tbody>"; echo "$tabs<tr><td class=\"value\">$tabs<table class=\"dump layout\">$tabs<tr><th>Parameters:</th><td>"; $params = $var->getParameters(); if (count($params) > 0) { echo "</td></tr>$tabs<tr><td colspan=\"2\">$tabs<table class=\"dump param\">$tabs<thead><tr><th>Name</th><th>Array/Ref</th><th>Required</th><th>Default</th></tr></thead>$tabs<tbody>"; foreach ($params as $param) { echo "$tabs<tr><td>" . htmlentities($param->getName()) . "</td><td>" . ($param->isArray() ? "Array " : "") . ($param->isPassedByReference() ? "Reference" : "") . "</td><td>" . ($param->isOptional() ? "Optional" : "Required") . "</td><td>"; if ($param->isOptional() && $param->isDefaultValueAvailable()) { $self->dump($param->getDefaultValue(), $limit, $label, $depth); } echo "</td></tr>"; } echo "$tabs</tbody>$tabs</table>"; } else { echo "none</td></tr>"; } $comment = trim($var->getDocComment()); if (($comment !== NULL) && ($comment !== '')) { echo "$tabs<tr><th>Doc Comment:</th><td><kbd>" . str_replace("\n", "<br/>", htmlentities($comment)) . "</kbd></td></tr>"; } echo "</table>$tabs</td></tr>"; echo "$tabs</tbody>$tabs</table>"; }; if (!array_key_exists('fw1dumpstarted', $_REQUEST)) { $_REQUEST['fw1dumpstarted'] = TRUE; echo<<<DUMPCSSJS <style type="text/css">/* fw/1 dump */ table.dump { color: black; background-color: white; font-size: xx-small; font-family: verdana,arial,helvetica,sans-serif; border-spacing: 0; border-collapse: collapse; } table.dump th { text-indent: -2em; padding: 0.25em 0.25em 0.25em 2.25em; color: #fff; } table.dump td { padding: 0.25em; } table.dump .key { cursor: pointer; } table.dump td.shh { background-color: #ddd; } table.dump td.shh div { display: none; } table.dump td.shh:before { content: "..."; } table.dump th, table.dump td { border-width: 2px; border-style: solid; border-spacing: 0; vertical-align: top; text-align: left; } table.dump.object, table.dump.object > * > tr > td, table.dump.object > thead > tr > th { border-color: #f00; } table.dump.object > thead > tr > th { background-color: #f44; } table.dump.object > tbody > tr > .key { background-color: #fcc; } table.dump.array, table.dump.array > * > tr > td, table.dump.array > thead > tr > th { border-color: #060; } table.dump.array > thead > tr > th { background-color: #090; } table.dump.array > tbody > tr > .key { background-color: #cfc; } table.dump.struct, table.dump.struct > * > tr > td, table.dump.struct > thead > tr > th { border-color: #00c; } table.dump.struct > thead > tr > th { background-color: #44c; } table.dump.struct > tbody > tr > .key { background-color: #cdf; } table.dump.function, table.dump.function > * > tr > td, table.dump.function > thead > tr > th { border-color: #a40; } table.dump.function > thead > tr > th { background-color: #c60; } table.dump.layout, table.dump.layout > * > tr > td, table.dump.layout > thead > tr > th { border-color: #fff; } table.dump.layout > * > tr > th { font-style: italic; background-color: #fff; color: #000; font-weight: normal; border: none; } table.dump.param, table.dump.param > * > tr > td, table.dump.param > thead > tr > th { border-color: #ddd; } table.dump.param > thead > tr > th { background-color: #eee; color: black; font-weight: bold; } </style> <script type="text/javascript" language="JavaScript"> (function(w,d){ var addEvent = function(o,t,f) { if (o.addEventListener) o.addEventListener(t,f,false); else if (o.attachEvent) { o['e' + t + f] = f; o[t + f] = function() { o['e' + t + f](w.event); } o.attachEvent('on' + t, o[t + f]); } }; // addEvent var clickCell = function(e) { var target = e.target || this; var sib = target.nextSibling; if (sib && sib.tagName && (sib.tagName.toLowerCase() === 'td')) { if (/(^|\s)shh(\s|$)/.test(sib.className)) sib.className = sib.className.replace(/(^|\s)shh(\s|$)/, ' '); else sib.className += ' shh'; } if (e && e.stopPropagation) e.stopPropagation(); else w.event.cancelBubble = true; return false; }; // clickCell var collapsifyDumps = function() { setTimeout(function() { var tables = document.getElementsByTagName('table'); for(var t = 0; t < tables.length; t++) { var table = tables[t]; var dumpPattern = /(^|\s)dump(\s|$)/; var depthPattern = /(^|\s)depth1(\s|$)/; if (! (dumpPattern.test(table.className) && depthPattern.test(table.className) )) continue; var cells = table.getElementsByTagName('td'); var keyPattern = /(^|\s)key(\s|$)/; var keyCount = 0; for (var c = 0; c < cells.length; c++) { var cell = cells[c]; if (! (keyPattern.test(cell.className))) continue; addEvent(cell, 'click', clickCell); } // for k } // for t }, 250); }; // collapsify dumps if (d.addEventListener) d.addEventListener("DOMContentLoaded", collapsifyDumps, false); else d.onreadystatechange = function() { if (d.readyState === 'interactive') collapsifyDumps(this); }; })(window,document); </script> DUMPCSSJS; } if (is_array($var)) { // It turns out that identity (===) in PHP isn't actually identity. It's more like "do you look similar enough to fool an untrained observer?". Lame! // $label = $label === '' ? (($var === $_POST) ? '$_POST' : (($var === $_GET) ? '$_GET' : (($var === $_COOKIE) ? '$_COOKIE' : (($var === $_ENV) ? '$_ENV' : (($var === $_FILES) ? '$_FILES' : (($var === $_REQUEST) ? '$_REQUEST' : (($var === $_SERVER) ? '$_SERVER' : (isset($_SESSION) && ($var === $_SESSION) ? '$_SESSION' : '')))))))) : $label; $c = count($var); if(isset($var['fw1recursionsentinel'])) { echo "(Recursion)"; } $aclass = (($c > 0) && array_key_exists(0, $var) && array_key_exists($c - 1, $var)) ? 'array' : 'struct'; $var['fw1recursionsentinel'] = TRUE; echo "$tabs<table class=\"dump ${aclass} depth${depth}\">$tabs<thead><tr><th colspan=\"2\">" . ($label != '' ? $label . ' - ' : '') . "array" . ($c > 0 ? "" : " [empty]") . "</th></tr></thead>$tabs<tbody>"; foreach ($var as $index => $aval) { if ($index === 'fw1recursionsentinel') continue; echo "$tabs<tr><td class=\"key\">" . $he($index) . "</td><td class=\"value\"><div>"; $this->dump($aval, $limit, '', $depth); echo "</div></td></tr>"; $printCount++; if (($limit > 0) && ($printCount >= $limit) && ($aclass === 'array')) break; } echo "$tabs</tbody>$tabs</table>"; // unset($var['fw1recursionsentinel']); } elseif (is_string($var)) { echo $var === '' ? '[EMPTY STRING]' : htmlentities($var); } elseif (is_bool($var)) { echo $var ? "TRUE" : "FALSE"; } elseif (is_callable($var) || (is_object($var) && is_subclass_of($var, 'ReflectionFunctionAbstract'))) { $echoFunction($var, $tabs, $limit, $label, $depth); } elseif (is_float($var)) { echo "(float) " . htmlentities($var); } elseif (is_int($var)) { echo "(int) " . htmlentities($var); } elseif (is_null($var)) { echo "NULL"; } elseif (is_object($var)) { $ref = new \ReflectionObject($var); $parent = $ref->getParentClass(); $interfaces = implode("<br/>implements ", $ref->getInterfaceNames()); /* try { $serial = serialize($var); } catch (\Exception $e) { $serial = 'hasclosure' . $ref->getName(); } $objHash = 'o' . md5($serial); */ $objHash = spl_object_hash($var); $refHash = 'r' . md5($ref); echo "$tabs<table class=\"dump object depth${depth}\"" . (isset($seen[$refHash]) ? "" : "id=\"$refHash\"") . ">$tabs<thead>$tabs<tr><th colspan=\"2\">" . ($label != '' ? $label . ' - ' : '') . "object " . htmlentities($ref->getName()) . ($parent ? "<br/>extends " .$parent->getName() : "") . ($interfaces !== '' ? "<br/>implements " . $interfaces : "") . "</th></tr>$tabs<tbody>"; if (isset($seen[$objHash])) { echo "$tabs<tr><td colspan=\"2\"><a href=\"#$refHash\">[see above for details]</a></td></tr>"; } else { $seen[$objHash] = TRUE; $constants = $ref->getConstants(); if (count($constants) > 0) { echo "$tabs<tr><td class=\"key\">CONSTANTS</td><td class=\"values\"><div>$tabs<table class=\"dump object\">"; foreach ($constants as $constant => $cval) { echo "$tabs<tr><td class=\"key\">" . htmlentities($constant) . "</td><td class=\"value constant\"><div>"; $this->dump($cval, $limit, '', $depth + 1); echo "</div></td></tr>"; } echo "$tabs</table>$tabs</div></td></tr>"; } $properties = $ref->getProperties(); if (count($properties) > 0) { echo "$tabs<tr><td class=\"key\">PROPERTIES</td><td class=\"values\"><div>$tabs<table class=\"dump object\">"; foreach ($properties as $property) { echo "$tabs<tr><td class=\"key\">" . htmlentities(implode(' ', \Reflection::getModifierNames($property->getModifiers()))) . " " . $he($property->getName()) . "</td><td class=\"value property\"><div>"; $wasHidden = $property->isPrivate() || $property->isProtected(); $property->setAccessible(TRUE); $propertyValue = $property->getValue($var); $this->dump($propertyValue, $limit, '', $depth + 1); if ($wasHidden) { $property->setAccessible(FALSE); } echo "</div></td></tr>"; } echo "$tabs</table>$tabs</div></td></tr>"; } $methods = $ref->getMethods(); if (count($methods) > 0) { echo "$tabs<tr><td class=\"key\">METHODS</td><td class=\"values shh\"><div>"; if (isset($seen[$refHash])) { echo "<a href=\"#$refHash\">[see above for details]</a>"; } else { $seen[$refHash] = TRUE; echo "$tabs<table class=\"dump object\">"; foreach ($methods as $method) { echo "$tabs<tr><td class=\"key\">" . htmlentities($method->getName()) . "</td><td class=\"value function\"><div>"; $echoFunction($method, $tabs, $limit, '', $depth + 1); echo "</div></td></tr>"; } echo "$tabs</table>"; } echo "$tabs</div></td></tr>"; } } echo "$tabs</tbody>$tabs</table>"; } elseif (is_resource($var)) { echo "(Resource)"; } elseif (is_numeric($var)) { echo htmlentities($var); } elseif (is_scalar($var)) { echo htmlentities($var); } else { echo gettype($var); } } // dump
function ws_generate_wsdl($wsdata) { require_once "wsdl/WS_WSDL_Creator.php"; require_once "wsdl/WS_WSDL_Consts.php"; require_once 'dynamic_invocation/wsf_wsdl_consts.php'; $service_name = $wsdata->serviceName; $fn_arry = $wsdata->WSDLGEN_Functions; $class_arry = $wsdata->WSDLGEN_Svcinfo_Classmap; $binding_style = $wsdata->WSDLGen_binding; $wsdl_version = $wsdata->WSDLGen_wsdlversion; $request_uri = $wsdata->WSDLGen_path; $op_arry = $wsdata->WSDLGen_operations; $classmap = $wsdata->WSDLGen_Classmap; $annotations = $wsdata->WSDLGen_annotations; $actions = $wsdata->WSDLGen_actions; $use_wsa = $wsdata->WSDLGen_usewsa; require_once "wsdl/WS_WSDL_Creator.php"; require_once "wsdl/WS_WSDL_Consts.php"; require_once 'dynamic_invocation/wsf_wsdl_consts.php'; $r_actions = NULL; if ($actions) { foreach ($actions as $act => $op) { $r_actions[$op] = $act; } } if ($binding_style == WS_WSDL_Const::WSF_WSDL_RPC_ENCODED) { $binding_style = WS_WSDL_Const::WSF_WSDL_RPC; } else { if ($binding_style == NULL) { $binding_style = WS_WSDL_Const::WSF_WSDL_DOCLIT; } } if ($binding_style != WS_WSDL_Const::WSF_WSDL_RPC && $binding_style != WS_WSDL_Const::WSF_WSDL_DOCLIT) { ws_log_write(__FILE__, __LINE__, WSF_LOG_ERROR, "Wrong binding style {$binding_style}"); echo "Error in generating the WSDL\n"; exit(0); } $namespace = WS_WSDL_Const::WS_WSDL_DEFAULT_NS; $first_class_name = ""; $first_op_name = ""; if ($class_arry && is_array($class_arry)) { foreach ($class_arry as $class_name => $value) { $first_class_name = $class_name; break; } } else { foreach ($op_arry as $svc_op_name => $op_name) { $first_op_name = $op_name; } } if ($first_class_name) { try { $class = new ReflectionClass($first_class_name); $class_comment = $class->getDocComment(); if (preg_match_all('|@namespace\\s+([^\\s]+).*|', $class_comment, $matches, PREG_SET_ORDER)) { $namespace = $matches[0][1]; } } catch (Exception $e) { //if the class doesn't exist, we just continue to use the default namespace } } else { if ($first_op_name) { try { $op = new ReflectionFunction($first_op_name); $op_comment = $op->getDocComment(); if (preg_match_all('|@namespace\\s+([^\\s]+).*|', $op_comment, $matches, PREG_SET_ORDER)) { $namespace = $matches[0][1]; } } catch (Exception $e) { //if the class doesn't exist, we just continue to use the default namespace } } } $wsdl = new WS_WSDL_Creator($fn_arry, $class_arry, $service_name, $request_uri, $binding_style, $namespace, $wsdl_version, $op_arry, $classmap, $annotations, $r_actions, $use_wsa); $wsdl_out = $wsdl->WS_WSDL_Out(); if (strcmp($wsdl_version, WS_WSDL_Const::WSF_WSDL_VERSION2_0) == 0) { $converted_wsdl = ws_convert_to_wsdl20($wsdl_out); return $converted_wsdl; } else { return $wsdl_out; } }
<?php /** test */ namespace foo; function test() { } $x = new \ReflectionFunction('foo\\test'); var_dump($x->getDocComment()); /** test1 */ class bar { } /** test2 */ class foo extends namespace\bar { } $x = new \ReflectionClass('foo\\bar'); var_dump($x->getDocComment()); $x = new \ReflectionClass('foo\\foo'); var_dump($x->getDocComment());
/** * handle the '?' commands * * With the help of the Reflection Class we extract the DocComments and display them * For internal Functions we extract the prototype from the php source. * * ? Class::method() * ? $obj->method() * ? Class::property * ? $obj::property * ? Class * ? $obj * ? function() * * The license of the PHP_Shell class * ? license * * @return string the help text */ public function cmdHelp($l) { if ("? " == substr($l, 0, strlen("? "))) { $str = substr($l, 2); $cmd = ''; if (preg_match('#^([A-Za-z0-9_]+)::([a-zA-Z0-9_]+)\\(\\s*\\)\\s*#', $str, $a)) { /* ? Class::method() */ $class = $a[1]; $method = $a[2]; if (false !== ($proto = PHP_ShellPrototypes::getInstance()->get($class . '::' . $method))) { $cmd = sprintf("/**\n* %s\n\n* @params %s\n* @return %s\n*/\n", $proto['description'], $proto['params'], $proto['return']); } else { if (class_exists($class, false)) { $c = new ReflectionClass($class); if ($c->hasMethod($method)) { $cmd = $c->getMethod($method)->getDocComment(); } } } } else { if (preg_match('#^\\$([A-Za-z0-9_]+)->([a-zA-Z0-9_]+)\\(\\s*\\)\\s*#', $str, $a)) { /* ? $obj->method() */ if (isset($GLOBALS[$a[1]]) && is_object($GLOBALS[$a[1]])) { $class = get_class($GLOBALS[$a[1]]); $method = $a[2]; $c = new ReflectionClass($class); if ($c->hasMethod($method)) { $cmd = $c->getMethod($method)->getDocComment(); } } } else { if (preg_match('#^([A-Za-z0-9_]+)::([a-zA-Z0-9_]+)\\s*$#', $str, $a)) { /* ? Class::property */ $class = $a[1]; $property = $a[2]; if (class_exists($class, false)) { $c = new ReflectionClass($class); if ($c->hasProperty($property)) { $cmd = $c->getProperty($property)->getDocComment(); } } } else { if (preg_match('#^\\$([A-Za-z0-9_]+)->([a-zA-Z0-9_]+)\\s*$#', $str, $a)) { /* ? $obj->property */ if (isset($GLOBALS[$a[1]]) && is_object($GLOBALS[$a[1]])) { $class = get_class($GLOBALS[$a[1]]); $method = $a[2]; $c = new ReflectionClass($class); if ($c->hasProperty($property)) { $cmd = $c->getProperty($property)->getDocComment(); } } } else { if (preg_match('#^([A-Za-z0-9_]+)$#', $str, $a)) { /* ? Class */ if (class_exists($a[1], false)) { $c = new ReflectionClass($a[1]); $cmd = $c->getDocComment(); } } else { if (preg_match('#^\\$([A-Za-z0-9_]+)$#', $str, $a)) { /* ? $object */ $obj = $a[1]; if (isset($GLOBALS[$obj]) && is_object($GLOBALS[$obj])) { $class = get_class($GLOBALS[$obj]); $c = new ReflectionClass($class); $cmd = $c->getDocComment(); } } else { if (preg_match('#^([A-Za-z0-9_]+)\\(\\s*\\)$#', $str, $a)) { /* ? function() */ $func = $a[1]; if (false !== ($proto = PHP_ShellPrototypes::getInstance()->get($func))) { $cmd = sprintf("/**\n* %s\n*\n* @params %s\n* @return %s\n*/\n", $proto['description'], $proto['params'], $proto['return']); } else { if (function_exists($func)) { $c = new ReflectionFunction($func); $cmd = $c->getDocComment(); } } } } } } } } } if ($cmd == '') { $cmd = var_export(sprintf('no help found for \'%s\'', $str), 1); } else { $cmd = var_export($cmd, 1); } } else { if ("?" == $l) { $cmd = $this->getHelp(); $cmd = var_export($cmd, 1); } } return $cmd; }
/** * Logs a call to a deprecated function. * The log message will be taken from the annotation. * * @return void */ public static function logDeprecatedFunction() { if (!$GLOBALS['TYPO3_CONF_VARS']['SYS']['enableDeprecationLog']) { return; } $trail = debug_backtrace(); if ($trail[1]['type']) { $function = new \ReflectionMethod($trail[1]['class'], $trail[1]['function']); } else { $function = new \ReflectionFunction($trail[1]['function']); } $msg = ''; if (preg_match('/@deprecated\\s+(.*)/', $function->getDocComment(), $match)) { $msg = $match[1]; } // Trigger PHP error with a short message: <function> is deprecated (called from <source>, defined in <source>) $errorMsg = 'Function ' . $trail[1]['function']; if ($trail[1]['class']) { $errorMsg .= ' of class ' . $trail[1]['class']; } $errorMsg .= ' is deprecated (called from ' . $trail[1]['file'] . '#' . $trail[1]['line'] . ', defined in ' . $function->getFileName() . '#' . $function->getStartLine() . ')'; // Write a longer message to the deprecation log: <function> <annotion> - <trace> (<source>) $logMsg = $trail[1]['class'] . $trail[1]['type'] . $trail[1]['function']; $logMsg .= '() - ' . $msg . ' - ' . \TYPO3\CMS\Core\Utility\DebugUtility::debugTrail(); $logMsg .= ' (' . substr($function->getFileName(), strlen(PATH_site)) . '#' . $function->getStartLine() . ')'; self::deprecationLog($logMsg); }
/** * Show reflection * * Show reflection * * <code> * Panda_Debug::reflect('BEAR_Form'); // Class * Panda_Debug::reflect($obj); // Objecy * Panda_Debug::reflect('p'); // Function * </code> * * @param string $target target * @param boll $cehckParent check parent class * * @return void */ public static function reflect($target, $cehckParent = false) { if (is_object($target)) { $target = get_class($target); } switch (true) { case function_exists($target): $ref = new ReflectionFunction($target); $info['name'] = $ref->isInternal() ? 'The internal ' : 'The user-defined '; $info['name'] .= $targetName = $ref->getName(); $info['declare in'] = $ref->getFileName() . ' lines ' . $ref->getStartLine() . ' to ' . $ref->getEndline(); $info['Documentation'] = $ref->getDocComment(); $statics = $ref->getStaticVariables(); if ($statics) { $info['Static variables'] = $statics; } $type = 'function'; break; case class_exists($target, false): $ref = new ReflectionClass($target); $type = 'class'; $info['name'] = $ref->isInternal() ? 'The internal ' : 'The user-defined '; $info['name'] .= $ref->isAbstract() ? ' abstract ' : ''; $info['name'] .= $ref->isFinal() ? ' final ' : ''; $info['name'] .= $ref->isInterface() ? 'interface ' : 'class '; $info['name'] .= $targetName = $ref->getName(); $info['declare in'] = $ref->getFileName() . ' lines ' . $ref->getStartLine() . ' to ' . $ref->getEndline(); $info['modifiers'] = Reflection::getModifierNames($ref->getModifiers()); $info['Documentation'] = $ref->getDocComment(); $info['Implements'] = $ref->getInterfaces(); $info['Constants'] = $ref->getConstants(); foreach ($ref->getProperties() as $prop) { // ReflectionProperty クラスのインスタンスを生成する $propRef = new ReflectionProperty($targetName, $prop->name); if ($propRef->isPublic()) { $porps[] = $prop->name; } } // $info['Public Properties'] = $porps; foreach ($ref->getMethods() as $method) { $methodRef = new ReflectionMethod($targetName, $method->name); if ($methodRef->isPublic() || $method->isStatic()) { $final = $method->isFinal() ? 'final ' : ''; $pubic = $method->isPublic() ? 'public ' : ''; $static = $method->isStatic() ? ' static ' : ''; $methods[] = sprintf("%s%s%s %s", $final, $pubic, $static, $method->name); } } $info['Public Methods'] = $methods; if ($ref->isInstantiable() && is_object($target)) { $info['isInstance ?'] = $ref->isInstance($target) ? 'yes' : 'no'; } if ($parent) { $info['parent'] .= $ref->getParentClass(); } break; default: $type = 'Invalid Object/Class'; $targetName = $target; $info = null; break; } print_a($info, "show_objects:1;label: Reflection of {$type} '{$targetName}'"); }
/** * Given a user-defined PHP function, create a PHP 'wrapper' function that can * be exposed as xmlrpc method from an xmlrpc_server object and called from remote * clients (as well as its corresponding signature info). * * Since php is a typeless language, to infer types of input and output parameters, * it relies on parsing the javadoc-style comment block associated with the given * function. Usage of xmlrpc native types (such as datetime.dateTime.iso8601 and base64) * in the @param tag is also allowed, if you need the php function to receive/send * data in that particular format (note that base64 encoding/decoding is transparently * carried out by the lib, while datetime vals are passed around as strings) * * Known limitations: * - requires PHP 5.0.3 + * - only works for user-defined functions, not for PHP internal functions * (reflection does not support retrieving number/type of params for those) * - functions returning php objects will generate special xmlrpc responses: * when the xmlrpc decoding of those responses is carried out by this same lib, using * the appropriate param in php_xmlrpc_decode, the php objects will be rebuilt. * In short: php objects can be serialized, too (except for their resource members), * using this function. * Other libs might choke on the very same xml that will be generated in this case * (i.e. it has a nonstandard attribute on struct element tags) * - usage of javadoc @param tags using param names in a different order from the * function prototype is not considered valid (to be fixed?) * * Note that since rel. 2.0RC3 the preferred method to have the server call 'standard' * php functions (ie. functions not expecting a single xmlrpcmsg obj as parameter) * is by making use of the functions_parameters_type class member. * * @param string $funcname the name of the PHP user function to be exposed as xmlrpc method; array($obj, 'methodname') and array('class', 'methodname') are ok too * @param string $newfuncname (optional) name for function to be created * @param array $extra_options (optional) array of options for conversion. valid values include: * bool return_source when true, php code w. function definition will be returned, not evaluated * bool encode_php_objs let php objects be sent to server using the 'improved' xmlrpc notation, so server can deserialize them as php objects * bool decode_php_objs --- WARNING !!! possible security hazard. only use it with trusted servers --- * bool suppress_warnings remove from produced xml any runtime warnings due to the php function being invoked * @return false on error, or an array containing the name of the new php function, * its signature and docs, to be used in the server dispatch map * * @todo decide how to deal with params passed by ref: bomb out or allow? * @todo finish using javadoc info to build method sig if all params are named but out of order * @todo add a check for params of 'resource' type * @todo add some trigger_errors / error_log when returning false? * @todo what to do when the PHP function returns NULL? we are currently returning an empty string value... * @todo add an option to suppress php warnings in invocation of user function, similar to server debug level 3? * @todo if $newfuncname is empty, we could use create_user_func instead of eval, as it is possibly faster * @todo add a verbatim_object_copy parameter to allow avoiding the same obj instance? */ function wrap_php_function($funcname, $newfuncname = '', $extra_options = array()) { $buildit = isset($extra_options['return_source']) ? !$extra_options['return_source'] : true; $prefix = isset($extra_options['prefix']) ? $extra_options['prefix'] : 'xmlrpc'; $encode_php_objects = isset($extra_options['encode_php_objs']) ? (bool) $extra_options['encode_php_objs'] : false; $decode_php_objects = isset($extra_options['decode_php_objs']) ? (bool) $extra_options['decode_php_objs'] : false; $catch_warnings = isset($extra_options['suppress_warnings']) && $extra_options['suppress_warnings'] ? '@' : ''; if (version_compare(phpversion(), '5.0.3') == -1) { // up to php 5.0.3 some useful reflection methods were missing error_log('XML-RPC: cannot not wrap php functions unless running php version bigger than 5.0.3'); return false; } $exists = false; if (is_string($funcname) && strpos($funcname, '::') !== false) { $funcname = explode('::', $funcname); } if (is_array($funcname)) { if (count($funcname) < 2 || !is_string($funcname[0]) && !is_object($funcname[0])) { error_log('XML-RPC: syntax for function to be wrapped is wrong'); return false; } if (is_string($funcname[0])) { $plainfuncname = implode('::', $funcname); } elseif (is_object($funcname[0])) { $plainfuncname = get_class($funcname[0]) . '->' . $funcname[1]; } $exists = method_exists($funcname[0], $funcname[1]); if (!$exists && version_compare(phpversion(), '5.1') < 0) { // workaround for php 5.0: static class methods are not seen by method_exists $exists = is_callable($funcname); } } else { $plainfuncname = $funcname; $exists = function_exists($funcname); } if (!$exists) { error_log('XML-RPC: function to be wrapped is not defined: ' . $plainfuncname); return false; } else { // determine name of new php function if ($newfuncname == '') { if (is_array($funcname)) { if (is_string($funcname[0])) { $xmlrpcfuncname = "{$prefix}_" . implode('_', $funcname); } else { $xmlrpcfuncname = "{$prefix}_" . get_class($funcname[0]) . '_' . $funcname[1]; } } else { $xmlrpcfuncname = "{$prefix}_{$funcname}"; } } else { $xmlrpcfuncname = $newfuncname; } while ($buildit && function_exists($xmlrpcfuncname)) { $xmlrpcfuncname .= 'x'; } // start to introspect PHP code if (is_array($funcname)) { $func = new ReflectionMethod($funcname[0], $funcname[1]); if ($func->isPrivate()) { error_log('XML-RPC: method to be wrapped is private: ' . $plainfuncname); return false; } if ($func->isProtected()) { error_log('XML-RPC: method to be wrapped is protected: ' . $plainfuncname); return false; } if ($func->isConstructor()) { error_log('XML-RPC: method to be wrapped is the constructor: ' . $plainfuncname); return false; } // php 503 always says isdestructor = true... if (version_compare(phpversion(), '5.0.3') != 0 && $func->isDestructor()) { error_log('XML-RPC: method to be wrapped is the destructor: ' . $plainfuncname); return false; } if ($func->isAbstract()) { error_log('XML-RPC: method to be wrapped is abstract: ' . $plainfuncname); return false; } /// @todo add more checks for static vs. nonstatic? } else { $func = new ReflectionFunction($funcname); } if ($func->isInternal()) { // Note: from PHP 5.1.0 onward, we will possibly be able to use invokeargs // instead of getparameters to fully reflect internal php functions ? error_log('XML-RPC: function to be wrapped is internal: ' . $plainfuncname); return false; } // retrieve parameter names, types and description from javadoc comments // function description $desc = ''; // type of return val: by default 'any' $returns = $GLOBALS['xmlrpcValue']; // desc of return val $returnsDocs = ''; // type + name of function parameters $paramDocs = array(); $docs = $func->getDocComment(); if ($docs != '') { $docs = explode("\n", $docs); $i = 0; foreach ($docs as $doc) { $doc = trim($doc, " \r\t/*"); if (strlen($doc) && strpos($doc, '@') !== 0 && !$i) { if ($desc) { $desc .= "\n"; } $desc .= $doc; } elseif (strpos($doc, '@param') === 0) { // syntax: @param type [$name] desc if (preg_match('/@param\\s+(\\S+)(\\s+\\$\\S+)?\\s+(.+)/', $doc, $matches)) { if (strpos($matches[1], '|')) { //$paramDocs[$i]['type'] = explode('|', $matches[1]); $paramDocs[$i]['type'] = 'mixed'; } else { $paramDocs[$i]['type'] = $matches[1]; } $paramDocs[$i]['name'] = trim($matches[2]); $paramDocs[$i]['doc'] = $matches[3]; } $i++; } elseif (strpos($doc, '@return') === 0) { // syntax: @return type desc //$returns = preg_split('/\s+/', $doc); if (preg_match('/@return\\s+(\\S+)\\s+(.+)/', $doc, $matches)) { $returns = php_2_xmlrpc_type($matches[1]); if (isset($matches[2])) { $returnsDocs = $matches[2]; } } } } } // execute introspection of actual function prototype $params = array(); $i = 0; foreach ($func->getParameters() as $paramobj) { $params[$i] = array(); $params[$i]['name'] = '$' . $paramobj->getName(); $params[$i]['isoptional'] = $paramobj->isOptional(); $i++; } // start building of PHP code to be eval'd $innercode = ''; $i = 0; $parsvariations = array(); $pars = array(); $pnum = count($params); foreach ($params as $param) { if (isset($paramDocs[$i]['name']) && $paramDocs[$i]['name'] && strtolower($paramDocs[$i]['name']) != strtolower($param['name'])) { // param name from phpdoc info does not match param definition! $paramDocs[$i]['type'] = 'mixed'; } if ($param['isoptional']) { // this particular parameter is optional. save as valid previous list of parameters $innercode .= "if (\$paramcount > {$i}) {\n"; $parsvariations[] = $pars; } $innercode .= "\$p{$i} = \$msg->getParam({$i});\n"; if ($decode_php_objects) { $innercode .= "if (\$p{$i}->kindOf() == 'scalar') \$p{$i} = \$p{$i}->scalarval(); else \$p{$i} = php_{$prefix}_decode(\$p{$i}, array('decode_php_objs'));\n"; } else { $innercode .= "if (\$p{$i}->kindOf() == 'scalar') \$p{$i} = \$p{$i}->scalarval(); else \$p{$i} = php_{$prefix}_decode(\$p{$i});\n"; } $pars[] = "\$p{$i}"; $i++; if ($param['isoptional']) { $innercode .= "}\n"; } if ($i == $pnum) { // last allowed parameters combination $parsvariations[] = $pars; } } $sigs = array(); $psigs = array(); if (count($parsvariations) == 0) { // only known good synopsis = no parameters $parsvariations[] = array(); $minpars = 0; } else { $minpars = count($parsvariations[0]); } if ($minpars) { // add to code the check for min params number // NB: this check needs to be done BEFORE decoding param values $innercode = "\$paramcount = \$msg->getNumParams();\n" . "if (\$paramcount < {$minpars}) return new {$prefix}resp(0, {$GLOBALS['xmlrpcerr']['incorrect_params']}, '{$GLOBALS['xmlrpcstr']['incorrect_params']}');\n" . $innercode; } else { $innercode = "\$paramcount = \$msg->getNumParams();\n" . $innercode; } $innercode .= "\$np = false;\n"; // since there are no closures in php, if we are given an object instance, // we store a pointer to it in a global var... if (is_array($funcname) && is_object($funcname[0])) { $GLOBALS['xmlrpcWPFObjHolder'][$xmlrpcfuncname] =& $funcname[0]; $innercode .= "\$obj =& \$GLOBALS['xmlrpcWPFObjHolder']['{$xmlrpcfuncname}'];\n"; $realfuncname = '$obj->' . $funcname[1]; } else { $realfuncname = $plainfuncname; } foreach ($parsvariations as $pars) { $innercode .= "if (\$paramcount == " . count($pars) . ") \$retval = {$catch_warnings}{$realfuncname}(" . implode(',', $pars) . "); else\n"; // build a 'generic' signature (only use an appropriate return type) $sig = array($returns); $psig = array($returnsDocs); for ($i = 0; $i < count($pars); $i++) { if (isset($paramDocs[$i]['type'])) { $sig[] = php_2_xmlrpc_type($paramDocs[$i]['type']); } else { $sig[] = $GLOBALS['xmlrpcValue']; } $psig[] = isset($paramDocs[$i]['doc']) ? $paramDocs[$i]['doc'] : ''; } $sigs[] = $sig; $psigs[] = $psig; } $innercode .= "\$np = true;\n"; $innercode .= "if (\$np) return new {$prefix}resp(0, {$GLOBALS['xmlrpcerr']['incorrect_params']}, '{$GLOBALS['xmlrpcstr']['incorrect_params']}'); else {\n"; //$innercode .= "if (\$_xmlrpcs_error_occurred) return new xmlrpcresp(0, $GLOBALS['xmlrpcerr']user, \$_xmlrpcs_error_occurred); else\n"; $innercode .= "if (is_a(\$retval, '{$prefix}resp')) return \$retval; else\n"; if ($returns == $GLOBALS['xmlrpcDateTime'] || $returns == $GLOBALS['xmlrpcBase64']) { $innercode .= "return new {$prefix}resp(new {$prefix}val(\$retval, '{$returns}'));"; } else { if ($encode_php_objects) { $innercode .= "return new {$prefix}resp(php_{$prefix}_encode(\$retval, array('encode_php_objs')));\n"; } else { $innercode .= "return new {$prefix}resp(php_{$prefix}_encode(\$retval));\n"; } } // shall we exclude functions returning by ref? // if($func->returnsReference()) // return false; $code = "function {$xmlrpcfuncname}(\$msg) {\n" . $innercode . "}\n}"; //print_r($code); if ($buildit) { $allOK = 0; eval($code . '$allOK=1;'); // alternative //$xmlrpcfuncname = create_function('$m', $innercode); if (!$allOK) { error_log('XML-RPC: could not create function ' . $xmlrpcfuncname . ' to wrap php function ' . $plainfuncname); return false; } } /// @todo examine if $paramDocs matches $parsvariations and build array for /// usage as method signature, plus put together a nice string for docs $ret = array('function' => $xmlrpcfuncname, 'signature' => $sigs, 'docstring' => $desc, 'signature_docs' => $psigs, 'source' => $code); return $ret; } }
function show_info($function, $basic = 0) { $func = new ReflectionFunction($function); $ret = ''; $ret .= "<pre><strong>Information:</strong>\n" . var_export($func->getDocComment(), 1) . "</pre>\n"; if ($basic) { $ret .= "<pre><pre>===> The " . ($func->isInternal() ? 'internal' : 'user-defined') . " function '" . $func->getName() . "'\n" . "\tdeclared in " . $func->getFileName() . "\n\tlines " . $func->getStartLine() . " to " . $func->getEndline() . "</pre>\n"; } return $ret; }
/** * Logs a call to a deprecated function. * The log message will be taken from the annotation. * * @return void */ public static function logDeprecatedFunction() { if (!$GLOBALS['TYPO3_CONF_VARS']['SYS']['enableDeprecationLog']) { return; } $trail = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2); if ($trail[1]['type']) { $function = new \ReflectionMethod($trail[1]['class'], $trail[1]['function']); } else { $function = new \ReflectionFunction($trail[1]['function']); } $msg = ''; if (preg_match('/@deprecated\\s+(.*)/', $function->getDocComment(), $match)) { $msg = $match[1]; } // Write a longer message to the deprecation log: <function> <annotion> - <trace> (<source>) $logMsg = $trail[1]['class'] . $trail[1]['type'] . $trail[1]['function']; $logMsg .= '() - ' . $msg . ' - ' . DebugUtility::debugTrail(); $logMsg .= ' (' . PathUtility::stripPathSitePrefix($function->getFileName()) . '#' . $function->getStartLine() . ')'; self::deprecationLog($logMsg); }
# ReflectionFunction. /** * This is f's doc comment. */ function &f($a, &$b, $c = null, $d = array(1, 2, SOME_CONSTANT)) { static $staticX = 4; static $staticY; print "In f()\n"; $staticX++; $x = $staticX; return $x; } $rf = new ReflectionFunction("f"); print "--- getDocComment(\"f\") ---\n"; var_dump($rf->getDocComment()); print "\n"; print "--- getStartLine(\"f\") ---\n"; var_dump($rf->getStartLine()); print "\n"; print "--- getEndLine(\"f\") ---\n"; var_dump($rf->getEndLine()); print "\n"; print "--- getFileName(\"f\") ---\n"; var_dump($rf->getFileName()); print "\n"; print "--- getName(\"f\") ---\n"; var_dump($rf->getName()); print "\n"; print "--- getNumberOfParameters(\"f\") ---\n"; var_dump($rf->getNumberOfParameters());
* Check Nette Framework requirements. */ $tests[] = array('title' => 'Web server', 'message' => isset($_SERVER['SERVER_SOFTWARE']) ? $_SERVER['SERVER_SOFTWARE'] : 'unknown'); $tests[] = array('title' => 'PHP version', 'required' => TRUE, 'passed' => version_compare(PHP_VERSION, '5.3.1', '>='), 'message' => PHP_VERSION, 'description' => 'Your PHP version is too old. Nette Framework requires at least PHP 5.3.1 or higher.'); $tests[] = array('title' => 'Memory limit', 'message' => ini_get('memory_limit')); $tests['hf'] = array('title' => '.htaccess file protection', 'required' => FALSE, 'description' => 'File protection by <code>.htaccess</code> is not present. You must be careful to put files into document_root folder.', 'script' => '<script src="assets/denied/checker.js"></script> <script>displayResult("hf", typeof fileProtectionChecker == "undefined")</script>'); $tests['hr'] = array('title' => '.htaccess mod_rewrite', 'required' => FALSE, 'description' => 'Mod_rewrite is probably not present. You will not be able to use Cool URL.', 'script' => '<script src="assets/rewrite/checker"></script> <script>displayResult("hr", typeof modRewriteChecker == "boolean")</script>'); $tests[] = array('title' => 'Function ini_set()', 'required' => FALSE, 'passed' => function_exists('ini_set'), 'description' => 'Function <code>ini_set()</code> is disabled. Some parts of Nette Framework may not work properly.'); $tests[] = array('title' => 'Function error_reporting()', 'required' => TRUE, 'passed' => function_exists('error_reporting'), 'description' => 'Function <code>error_reporting()</code> is disabled. Nette Framework requires this to be enabled.'); $tests[] = array('title' => 'Function flock()', 'required' => TRUE, 'passed' => flock(fopen(__FILE__, 'r'), LOCK_SH), 'description' => 'Function <code>flock()</code> is not supported on this filesystem. Nette Framework requires this to process atomic file operations.'); $tests[] = array('title' => 'Register_globals', 'required' => TRUE, 'passed' => !iniFlag('register_globals'), 'message' => 'Disabled', 'errorMessage' => 'Enabled', 'description' => 'Configuration directive <code>register_globals</code> is enabled. Nette Framework requires this to be disabled.'); $tests[] = array('title' => 'Variables_order', 'required' => TRUE, 'passed' => strpos(ini_get('variables_order'), 'G') !== FALSE && strpos(ini_get('variables_order'), 'P') !== FALSE && strpos(ini_get('variables_order'), 'C') !== FALSE, 'description' => 'Configuration directive <code>variables_order</code> is missing. Nette Framework requires this to be set.'); $tests[] = array('title' => 'Session auto-start', 'required' => FALSE, 'passed' => session_id() === '' && !defined('SID'), 'description' => 'Session auto-start is enabled. Nette Framework recommends not to use this directive for security reasons.'); $tests[] = array('title' => 'PCRE with UTF-8 support', 'required' => TRUE, 'passed' => @preg_match('/pcre/u', 'pcre'), 'description' => 'PCRE extension must support UTF-8.'); $reflection = new ReflectionFunction('paint'); $tests[] = array('title' => 'Reflection phpDoc', 'required' => TRUE, 'passed' => strpos($reflection->getDocComment(), 'Paints') !== FALSE, 'description' => 'Reflection phpDoc are not available (probably due to an eAccelerator bug). You cannot use @annotations.'); $tests[] = array('title' => 'ICONV extension', 'required' => TRUE, 'passed' => extension_loaded('iconv') && ICONV_IMPL !== 'unknown' && @iconv('UTF-16', 'UTF-8//IGNORE', iconv('UTF-8', 'UTF-16//IGNORE', 'test')) === 'test', 'message' => 'Enabled and works properly', 'errorMessage' => 'Disabled or does not work properly', 'description' => 'ICONV extension is required and must work properly.'); $tests[] = array('title' => 'JSON extension', 'required' => TRUE, 'passed' => extension_loaded('json')); $tests[] = array('title' => 'Fileinfo extension', 'required' => FALSE, 'passed' => extension_loaded('fileinfo'), 'description' => 'Fileinfo extension is absent. You will not be able to detect content-type of uploaded files.'); $tests[] = array('title' => 'PHP tokenizer', 'required' => TRUE, 'passed' => extension_loaded('tokenizer'), 'description' => 'PHP tokenizer is required.'); $tests[] = array('title' => 'PDO extension', 'required' => FALSE, 'passed' => $pdo = extension_loaded('pdo') && PDO::getAvailableDrivers(), 'message' => $pdo ? 'Available drivers: ' . implode(' ', PDO::getAvailableDrivers()) : NULL, 'description' => 'PDO extension or PDO drivers are absent. You will not be able to use <code>Nette\\Database</code>.'); $tests[] = array('title' => 'Multibyte String extension', 'required' => FALSE, 'passed' => extension_loaded('mbstring'), 'description' => 'Multibyte String extension is absent. Some internationalization components may not work properly.'); $tests[] = array('title' => 'Multibyte String function overloading', 'required' => TRUE, 'passed' => !extension_loaded('mbstring') || !(mb_get_info('func_overload') & 2), 'message' => 'Disabled', 'errorMessage' => 'Enabled', 'description' => 'Multibyte String function overloading is enabled. Nette Framework requires this to be disabled. If it is enabled, some string function may not work properly.'); $tests[] = array('title' => 'Memcache extension', 'required' => FALSE, 'passed' => extension_loaded('memcache'), 'description' => 'Memcache extension is absent. You will not be able to use <code>Nette\\Caching\\Storages\\MemcachedStorage</code>.'); $tests[] = array('title' => 'GD extension', 'required' => FALSE, 'passed' => extension_loaded('gd'), 'description' => 'GD extension is absent. You will not be able to use <code>Nette\\Image</code>.'); $tests[] = array('title' => 'Bundled GD extension', 'required' => FALSE, 'passed' => extension_loaded('gd') && GD_BUNDLED, 'description' => 'Bundled GD extension is absent. You will not be able to use some functions such as <code>Nette\\Image::filter()</code> or <code>Nette\\Image::rotate()</code>.'); $tests[] = array('title' => 'Fileinfo extension or mime_content_type()', 'required' => FALSE, 'passed' => extension_loaded('fileinfo') || function_exists('mime_content_type'), 'description' => 'Fileinfo extension or function <code>mime_content_type()</code> are absent. You will not be able to determine mime type of uploaded files.'); $tests[] = array('title' => 'HTTP_HOST or SERVER_NAME', 'required' => TRUE, 'passed' => isset($_SERVER['HTTP_HOST']) || isset($_SERVER['SERVER_NAME']), 'message' => 'Present', 'errorMessage' => 'Absent', 'description' => 'Either <code>$_SERVER["HTTP_HOST"]</code> or <code>$_SERVER["SERVER_NAME"]</code> must be available for resolving host name.'); $tests[] = array('title' => 'REQUEST_URI or ORIG_PATH_INFO', 'required' => TRUE, 'passed' => isset($_SERVER['REQUEST_URI']) || isset($_SERVER['ORIG_PATH_INFO']), 'message' => 'Present', 'errorMessage' => 'Absent', 'description' => 'Either <code>$_SERVER["REQUEST_URI"]</code> or <code>$_SERVER["ORIG_PATH_INFO"]</code> must be available for resolving request URL.'); $tests[] = array('title' => 'SCRIPT_NAME or DOCUMENT_ROOT & SCRIPT_FILENAME', 'required' => TRUE, 'passed' => isset($_SERVER['SCRIPT_NAME']) || isset($_SERVER['DOCUMENT_ROOT'], $_SERVER['SCRIPT_FILENAME']), 'message' => 'Present', 'errorMessage' => 'Absent', 'description' => '<code>$_SERVER["SCRIPT_NAME"]</code> or <code>$_SERVER["DOCUMENT_ROOT"]</code> with <code>$_SERVER["SCRIPT_FILENAME"]</code> must be available for resolving script file path.'); $tests[] = array('title' => 'REMOTE_ADDR or php_uname("n")', 'required' => TRUE, 'passed' => isset($_SERVER['REMOTE_ADDR']) || function_exists('php_uname'), 'message' => 'Present', 'errorMessage' => 'Absent', 'description' => '<code>$_SERVER["REMOTE_ADDR"]</code> or <code>php_uname("n")</code> must be available for detecting development / production mode.');
<?php /** * Created by PhpStorm. * User: oneFORall * Date: 22.06.2015 * Time: 17:41 */ function func() { } $obj = new ReflectionFunction("func"); echo "<pre>" . $obj->getDocComment();
/** * Logs a call to a deprecated function. * The log message will be taken from the annotation. * * @return void */ public static function logDeprecatedFunction() { if (!$GLOBALS['TYPO3_CONF_VARS']['SYS']['enableDeprecationLog']) { return; } // This require_once is needed for deprecation calls // thrown early during bootstrap, if the autoloader is // not instantiated yet. This can happen for example if // ext_localconf triggers a deprecation. require_once 'DebugUtility.php'; $trail = debug_backtrace(); if ($trail[1]['type']) { $function = new \ReflectionMethod($trail[1]['class'], $trail[1]['function']); } else { $function = new \ReflectionFunction($trail[1]['function']); } $msg = ''; if (preg_match('/@deprecated\\s+(.*)/', $function->getDocComment(), $match)) { $msg = $match[1]; } // Write a longer message to the deprecation log: <function> <annotion> - <trace> (<source>) $logMsg = $trail[1]['class'] . $trail[1]['type'] . $trail[1]['function']; $logMsg .= '() - ' . $msg . ' - ' . \TYPO3\CMS\Core\Utility\DebugUtility::debugTrail(); $logMsg .= ' (' . \TYPO3\CMS\Core\Utility\PathUtility::stripPathSitePrefix($function->getFileName()) . '#' . $function->getStartLine() . ')'; self::deprecationLog($logMsg); }
/** * cfdump-style debugging output * @param $var The variable to output. * @param $limit Maximum recursion depth for arrays (default 0 = all) * @param $label text to display in complex data type header * @param $depth Current depth (default 0) */ public function dump(&$var, $limit = 0, $label = '', $depth = 0) { if ($limit > 0 && $depth >= $limit) { return; } static $seen = array(); $he = function ($s) { return htmlentities($s); }; $self = $this; $echoFunction = function ($var, $tabs, $label = '') use($self) { if (!is_subclass_of($var, 'ReflectionFunctionAbstract')) { $var = new \ReflectionFunction($var); } echo "{$tabs}<table class=\"dump function\">{$tabs}<thead><tr><th>" . ($label != '' ? $label . ' - ' : '') . (is_callable(array($var, 'getModifiers')) ? htmlentities(implode(' ', \Reflection::getModifierNames($var->getModifiers()))) : '') . " function " . htmlentities($var->getName()) . "</th></tr></thead>{$tabs}<tbody>"; echo "{$tabs}<tr><td class=\"value\">{$tabs}<table class=\"dump layout\">{$tabs}<tr><th>Parameters:</th><td>"; $params = $var->getParameters(); if (count($params) > 0) { echo "</td></tr>{$tabs}<tr><td colspan=\"2\">{$tabs}<table class=\"dump param\">{$tabs}<thead><tr><th>Name</th><th>Array/Ref</th><th>Required</th><th>Default</th></tr></thead>{$tabs}<tbody>"; foreach ($params as $param) { echo "{$tabs}<tr><td>" . htmlentities($param->getName()) . "</td><td>" . ($param->isArray() ? "Array " : "") . ($param->isPassedByReference() ? "Reference" : "") . "</td><td>" . ($param->isOptional() ? "Optional" : "Required") . "</td><td>"; if ($param->isOptional()) { $self->dump($param->getDefaultValue()); } echo "</td></tr>"; } echo "{$tabs}</tbody>{$tabs}</table>"; } else { echo "none</td></tr>"; } $comment = trim($var->getDocComment()); if ($comment !== NULL && $comment !== '') { echo "{$tabs}<tr><th>Doc Comment:</th><td><kbd>" . str_replace("\n", "<br/>", htmlentities($comment)) . "</kbd></td></tr>"; } echo "</table>{$tabs}</td></tr>"; echo "{$tabs}</tbody>{$tabs}</table>"; }; $tabs = "\n" . str_repeat("\t", $depth); $depth++; $printCount = 0; if (!array_key_exists('fw1dumpstarted', $_REQUEST)) { $_REQUEST['fw1dumpstarted'] = TRUE; echo <<<DUMPCSS <style type="text/css">/* fw/1 dump */ table.dump { color: black; background-color: white; font-size: xx-small; font-family: verdana,arial,helvetica,sans-serif; border-spacing: 0; border-collapse: collapse; } table.dump th { text-indent: -2em; padding: 0.25em 0.25em 0.25em 2.25em; color: #fff; } table.dump td { padding: 0.25em; } table.dump th, table.dump td { border-width: 2px; border-style: solid; border-spacing: 0; vertical-align: top; text-align: left; } table.dump.object, table.dump.object td, table.dump.object th { border-color: #f00; } table.dump.object th { background-color: #f44; } table.dump.object .key { background-color: #fcc; } table.dump.array, table.dump.array td, table.dump.array th { border-color: #060; } table.dump.array th { background-color: #090; } table.dump.array .key { background-color: #cfc; } table.dump.struct, table.dump.struct td, table.dump.struct th { border-color: #00c; } table.dump.struct th { background-color: #44c; } table.dump.struct .key { background-color: #cdf; } table.dump.function, table.dump.function td, table.dump.function th { border-color: #a40; } table.dump.function th { background-color: #c60; } table.dump.layout, table.dump.layout td, table.dump.layout th { border-color: #fff; } table.dump.layout th { font-style: italic; background-color: #fff; color: #000; font-weight: normal; } table.dump.param, table.dump.param td, table.dump.param th { border-color: #ddd; } table.dump.param th { background-color: #eee; color: black; font-weight: bold; } </style> DUMPCSS; } if (is_array($var)) { $label = $label === '' ? $var === $_POST ? '$_POST' : ($var === $_GET ? '$_GET' : ($var === $_COOKIE ? '$_COOKIE' : ($var === $_ENV ? '$_ENV' : ($var === $_FILES ? '$_FILES' : ($var === $_REQUEST ? '$_REQUEST' : ($var === $_SERVER ? '$_SERVER' : ($var === $_SESSION ? '$_SESSION' : ''))))))) : $label; $c = count($var); if (isset($var['fw1recursionsentinel'])) { echo "(Recursion)"; } $aclass = $c > 0 && array_key_exists(0, $var) && array_key_exists($c - 1, $var) ? 'array' : 'struct'; $var['fw1recursionsentinel'] = true; echo "{$tabs}<table class=\"dump {$aclass}\">{$tabs}<thead><tr><th colspan=\"2\">" . ($label != '' ? $label . ' - ' : '') . "array" . ($c > 0 ? "" : " [empty]") . "</th></tr></thead>{$tabs}<tbody>"; foreach ($var as $index => $aval) { if ($index === 'fw1recursionsentinel') { continue; } echo "{$tabs}<tr><td class=\"key\">" . $he($index) . "</td><td class=\"value\">"; $this->dump($aval, $limit, '', $depth); echo "</td></tr>"; $printCount++; if ($limit > 0 && $printCount >= $limit && $aclass === 'array') { break; } } echo "{$tabs}</tbody>{$tabs}</table>"; // unset($var['fw1recursionsentinel']); } elseif (is_string($var)) { echo $var === '' ? '[EMPTY STRING]' : htmlentities($var); } elseif (is_bool($var)) { echo $var ? "TRUE" : "FALSE"; } elseif (is_callable($var) || is_object($var) && is_subclass_of($var, 'ReflectionFunctionAbstract')) { $echoFunction($var, $tabs, $label); } elseif (is_float($var)) { echo "(float) " . htmlentities($var); } elseif (is_int($var)) { echo "(int) " . htmlentities($var); } elseif (is_null($var)) { echo "NULL"; } elseif (is_object($var)) { $ref = new \ReflectionObject($var); $parent = $ref->getParentClass(); $interfaces = implode("<br/>implements ", $ref->getInterfaceNames()); try { $serial = serialize($var); } catch (\Exception $e) { $serial = 'hasclosure' . $ref->getName(); } $objHash = 'o' . md5($serial); $refHash = 'r' . md5($ref); echo "{$tabs}<table class=\"dump object\"" . (isset($seen[$refHash]) ? "" : "id=\"{$refHash}\"") . ">{$tabs}<thead>{$tabs}<tr><th colspan=\"2\">" . ($label != '' ? $label . ' - ' : '') . "object " . htmlentities($ref->getName()) . ($parent ? "<br/>extends " . $parent->getName() : "") . ($interfaces !== '' ? "<br/>implements " . $interfaces : "") . "</th></tr>{$tabs}<tbody>"; if (isset($seen[$objHash])) { echo "{$tabs}<tr><td colspan=\"2\"><a href=\"#{$refHash}\">[see above for details]</a></td></tr>"; } else { $seen[$objHash] = TRUE; $constants = $ref->getConstants(); if (count($constants) > 0) { echo "{$tabs}<tr><td class=\"key\">CONSTANTS</td><td class=\"values\">{$tabs}<table class=\"dump object\">"; foreach ($constants as $constant => $cval) { echo "{$tabs}<tr><td class=\"key\">" . htmlentities($constant) . "</td><td class=\"value constant\">"; $this->dump($cval, $limit, '', $depth); echo "</td></tr>"; } echo "{$tabs}</table>{$tabs}</td></tr>"; } $properties = $ref->getProperties(); if (count($properties) > 0) { echo "{$tabs}<tr><td class=\"key\">PROPERTIES</td><td class=\"values\">{$tabs}<table class=\"dump object\">"; foreach ($properties as $property) { echo "{$tabs}<tr><td class=\"key\">" . htmlentities(implode(' ', \Reflection::getModifierNames($property->getModifiers()))) . " " . $he($property->getName()) . "</td><td class=\"value property\">"; $wasHidden = $property->isPrivate() || $property->isProtected(); $property->setAccessible(TRUE); $this->dump($property->getValue($var), $limit, '', $depth); if ($wasHidden) { $property->setAccessible(FALSE); } echo "</td></tr>"; } echo "{$tabs}</table>{$tabs}</td></tr>"; } $methods = $ref->getMethods(); if (count($methods) > 0) { echo "{$tabs}<tr><td class=\"key\">METHODS</td><td class=\"values\">"; if (isset($seen[$refHash])) { echo "<a href=\"#{$refHash}\">[see above for details]</a>"; } else { $seen[$refHash] = TRUE; echo "{$tabs}<table class=\"dump object\">"; foreach ($methods as $method) { echo "{$tabs}<tr><td class=\"key\">" . htmlentities($method->getName()) . "</td><td class=\"value function\">"; $echoFunction($method, $tabs, ''); echo "</td></tr>"; } echo "{$tabs}</table>"; } echo "{$tabs}</td></tr>"; } } echo "{$tabs}</tbody>{$tabs}</table>"; } elseif (is_resource($var)) { echo "(Resource)"; } elseif (is_numeric($var)) { echo htmlentities($var); } elseif (is_scalar($var)) { echo htmlentities($var); } else { echo gettype($var); } }