hphp/runtime/ext/reflection/ext_reflection_hni.php (1,112 lines of code) (raw):

<?hh // partial /** * ( excerpt from * http://php.net/manual/en/class.reflectionfunctionabstract.php ) * * A parent class to ReflectionFunction and ParentMethod. Read their * descriptions for details. */ <<__NativeData('ReflectionFuncHandle')>> abstract class ReflectionFunctionAbstract implements Reflector { const IS_STATIC = 1; const IS_PUBLIC = 256; const IS_PROTECTED = 512; const IS_PRIVATE = 1024; const IS_ABSTRACT = 2; const IS_FINAL = 4; /** * (excerpt from * http://php.net/manual/en/reflectionfunctionabstract.getname.php ) * * Get the name of the function. Warning: This function is currently not * documented; only its argument list is available. * * @return string The name of the function. */ <<__Native>> public function getName()[]: string; /** * ( excerpt from http://php.net/manual/en/reflectionfunctionabstract.innamespace.php * ) * * Checks whether a function is defined in a namespace. * * @return bool Returns TRUE on success or FALSE on failure. */ public function inNamespace()[]: bool { return strrpos($this->getName(), '\\') !== false; } /** * ( excerpt from * http://php.net/manual/en/reflectionfunctionabstract.getnamespacename.php ) * * Get the namespace name where the function is defined. * * @return string The namespace name. */ public function getNamespaceName()[]: string { $name = $this->getName(); $pos = strrpos($name, '\\'); return ($pos === false) ? '' : substr($name, 0, $pos); } /** * ( excerpt from * http://php.net/manual/en/reflectionfunctionabstract.getshortname.php ) * * Get the short name of the function (without the namespace part). * * @return string The short name of the function. */ public function getShortName()[]: string { $name = $this->getName(); $pos = strrpos($name, '\\'); return ($pos === false) ? $name : substr($name, $pos + 1); } <<__Native>> public function isHack()[]: bool; /** * ( excerpt from * http://php.net/manual/en/reflectionfunctionabstract.isinternal.php ) * * Checks whether the function is internal, as opposed to user-defined. * Warning: This function is currently not documented; only its argument * list is available. * * @return mixed TRUE if it's internal, otherwise FALSE */ <<__Native>> public function isInternal()[]: bool; /** * ( excerpt from * http://php.net/manual/en/reflectionfunctionabstract.isclosure.php ) * * Checks whether it's a closure. Warning: This function is currently not * documented; only its argument list is available. * * @return bool TRUE if it's a closure, otherwise FALSE */ public function isClosure()[]: bool { return false; } /** * ( excerpt from * http://php.net/manual/en/reflectionfunctionabstract.isgenerator.php ) * * Warning: This function is currently not documented; only its argument * list is available. * * @return bool TRUE if the function is generator, otherwise FALSE. */ <<__Native>> public function isGenerator()[]: bool; /** * @return bool TRUE if the function is async, otherwise FALSE. */ <<__Native>> public function isAsync()[]: bool; /** * Indicates whether the function has ...$varargs as its last parameter * to capture variadic arguments. * * @return bool TRUE if the function is variadic, otherwise FALSE */ <<__Native>> public function isVariadic()[]: bool; /** * ( excerpt from * http://php.net/manual/en/reflectionfunctionabstract.isuserdefined.php ) * * Checks whether the function is user-defined, as opposed to internal. * Warning: This function is currently not documented; only its argument * list is available. * * @return mixed TRUE if it's user-defined, otherwise false; */ public function isUserDefined()[]: bool { return !$this->isInternal(); } /** * ( excerpt from * http://php.net/manual/en/reflectionfunctionabstract.getfilename.php ) * * Gets the file name from a user-defined function. Warning: This function * is currently not documented; only its argument list is available. * * @return mixed The file name. */ <<__Native>> public function getFileName()[]: mixed; /** * Gets the declaring file for a user-defined function. * * @return ReflectionFile A ReflectionFile object of the file that the * reflected function is part of. */ public function getFile()[]: ReflectionFile { $fileName = $this->getFileName(); if ($fileName === false) { throw new ReflectionException( 'Couldn\'t get ReflectionFile because the function was not defined in '. 'a file.' ); } if (!is_string($fileName)) { throw new ReflectionException( 'Unexpected non-string file name for ReflectionFunction.' ); } return new ReflectionFile((string)$fileName); } /** * ( excerpt from * http://php.net/manual/en/reflectionfunctionabstract.getstartline.php ) * * Gets the starting line number of the function. Warning: This function * is currently not documented; only its argument list is available. * * @return mixed The starting line number. */ <<__Native>> public function getStartLine()[]: mixed; /** * ( excerpt from * http://php.net/manual/en/reflectionfunctionabstract.getendline.php ) * * Get the ending line number. Warning: This function is currently not * documented; only its argument list is available. * * @return mixed The ending line number of the user defined function, * or FALSE if unknown. */ <<__Native>> public function getEndLine()[]: mixed; /** * ( excerpt from * http://php.net/manual/en/reflectionfunctionabstract.getdoccomment.php ) * * Get a Doc comment from a function. Warning: This function is currently * not documented; only its argument list is available. * * @return mixed The doc comment string if it exists, otherwise FALSE */ <<__Native>> public function getDocComment()[]: mixed; <<__Native>> private function getRetTypeInfo()[]: dict; <<__Native>> private function getReturnTypeHint()[]: string; public function getReturnTypeText()[] { return $this->getReturnTypeHint() ?: false; } <<__Native>> public function getReifiedTypeParamInfo()[]: varray; <<__Native>> public function getCoeffects()[]: vec; /* * Returns the module associated with the given function. */ <<__Native>> public function getModule()[]: ?string; <<__Native>> public function returnsReadonly()[]: bool; /** * ( excerpt from * http://php.net/manual/en/reflectionfunctionabstract.hasreturntype.php * ) * * Checks if the function has a specified return type. * * @return - true if the function has a specified return type; false * otherwise. */ public function hasReturnType()[]: bool { return (bool) $this->getReturnTypeText(); } /** * ( excerpt from * http://php.net/manual/en/reflectionfunctionabstract.getReturnType.php * ) * * Gets the specified return type of a function * * @return - a ReflectionType object if a return type is specified; null * otherwise. */ public function getReturnType()[]: ?ReflectionType { if ($this->hasReturnType()) { $retTypeInfo = $this->getRetTypeInfo(); return new ReflectionType( $this, darray[ 'name' => $retTypeInfo['type_hint'], 'nullable' => $retTypeInfo['type_hint_nullable'], 'builtin' => $retTypeInfo['type_hint_builtin'], ] ); } return null; } /** * ( excerpt from * http://php.net/manual/en/reflectionclass.getattributes.php ) * * Gets all attributes * * @return array<arraykey, array<mixed>> */ <<__Native>> final public function getAttributesNamespaced()[]: darray<arraykey, varray<mixed>>; use ReflectionLegacyAttribute; <<__Native>> public function getNumberOfParameters()[]: int; <<__Native>> private function getParamInfo()[]: varray<darray<string, mixed>>; /** * ( excerpt from * http://php.net/manual/en/reflectionfunctionabstract.getparameters.php ) * * Get the parameters as an array of ReflectionParameter. Warning: This * function is currently not documented; only its argument list is * available. * * @return array The parameters, as a ReflectionParameter object. */ <<__Memoize>> public function getParameters()[]: varray<ReflectionParameter> { // FIXME: ReflectionParameter sh/could have native data pointing to the // relevant Func::ParamInfo data structure $ret = varray[]; foreach ($this->getParamInfo() as $idx => $info) { $param = new ReflectionParameter(null, null, $info); $ret[] = $param; } return $ret; } /** * ( excerpt from * http://php.net/manual/en/reflectionfunctionabstract.getnumberofrequiredparameters.php * ) * * Get the number of required parameters that a function defines. Warning: * This function is currently not documented; only its argument list is * available. * * @return mixed The number of required parameters. */ public function getNumberOfRequiredParameters()[] { $count = 0; $params = $this->getParameters(); foreach ($params as $name => $param) { if ($param->isOptional()) { break; } $count++; } return $count; } /** * ( excerpt from * http://php.net/manual/en/reflectionfunctionabstract.isdeprecated.php * ) * * Returns whether the function is deprecated. */ public function isDeprecated()[]: bool { return null !== $this->getAttribute('__Deprecated'); } public function getExtension()[] { // FIXME: HHVM doesn't support this return null; } public function getExtensionName()[] { return null; } /** * ( excerpt from * http://php.net/manual/en/reflectionfunctionabstract.getclosurescopeclass.php * ) * * Returns the scope associated to the closure * * @return mixed Returns the class on success or NULL on failure. */ public function getClosureScopeClass()[]: ?ReflectionClass { return null; } // Prevent cloning final public function __clone() { throw new BadMethodCallException( 'Trying to clone an uncloneable object of class ' . get_class($this) ); } // Implementation of __toString final protected function __toStringHelper( $type, varray<string> $preAttrs = varray[], varray<string> $funcAttrs = varray[], )[]: string { $ret = ''; if ($doc = $this->getDocComment()) { $ret .= $doc . "\n"; } $ret .= "$type [ <"; if ($this->isInternal()) { $ret .= 'internal'; if ($this->isDeprecated()) { $ret .= ', deprecated'; } if ($extensionName = $this->getExtensionName()) { $ret .= ':' . $extensionName; } } else { $ret .= 'user'; } if ($preAttrs) { $ret .= ', ' . implode(', ', $preAttrs); } $ret .= '> '; if ($funcAttrs) { $ret .= implode(' ', $funcAttrs) . ' '; } $ret .= ($type == 'Method') ? 'method ' : 'function '; $ret .= $this->getName() . " ] {\n"; if ((int)$this->getStartLine() > 0) { $file = (string)$this->getFileName(); $start = (string)$this->getStartLine(); $end = (string)$this->getEndLine(); $ret .= " @@ $file $start - $end\n"; } if ($this->isClosure()) { // TODO: Not enough info } $params = $this->getParameters(); if (count($params) > 0) { $ret .= "\n - Parameters [" . count($params) . "] {\n "; foreach ($params as $param) { $ret .= ' '.str_replace("\n", "\n ", $param->toString()."\n"); } $ret .= "}\n"; } $ret .= "}\n"; return $ret; } } /** * ( excerpt from http://php.net/manual/en/class.reflectionfunction.php ) * * The ReflectionFunction class reports information about a function. */ class ReflectionFunction extends ReflectionFunctionAbstract { public string $name; // should be readonly (PHP compatibility) private ?Closure $closure = null; /** * ( excerpt from http://php.net/manual/en/reflectionfunction.construct.php * ) * * Constructs a ReflectionFunction object. * * @name mixed The name of the function to reflect or a closure. * * @return mixed No value is returned. */ public function __construct($name_or_closure)[] { if ($name_or_closure is Closure) { $this->closure = $name_or_closure; $this->__initClosure($name_or_closure); } else if (is_string($name_or_closure)){ if (!$this->__initName($name_or_closure)) { throw new ReflectionException( "Function $name_or_closure does not exist"); } } else { throw new ReflectionException( sprintf('%s expects a string or a Closure, got %s', __METHOD__, gettype($name_or_closure)) ); } $this->name = $this->getName(); } <<__Native>> private function __initClosure(object $closure)[write_this_props]: bool; <<__Native>> private function __initName(string $name)[write_this_props]: bool; /** * (excerpt from * http://php.net/manual/en/reflectionfunctionabstract.getname.php ) * * Get the name of the function. Warning: This function is currently not * documented; only its argument list is available. * * @return string The name of the function. */ public function getName()[]: string { if ($this->closure) { // Format: Closure$scope;hash $cls = get_class($this->closure); $ns_end = strrpos($cls, '\\'); if ($ns_end !== false) { $ns_start = strpos($cls, '$') + 1; $ns = substr($cls, $ns_start, $ns_end - $ns_start); return $ns.'\\{closure}'; } return '{closure}'; } return parent::getName(); } public function getClosure() { return $this->closure ?: function(...$args) { return $this->invokeArgs($args); }; } <<__Pure, __MaybeMutable>> public function isClosure(): bool { return (bool) $this->closure; } /** * ( excerpt from http://php.net/manual/en/reflectionfunction.tostring.php ) * * @return string A representation of this ReflectionFunction. */ public function __toString()[]: string { return $this->__toStringHelper($this->isClosure() ? 'Closure' : 'Function'); } /** * ( excerpt from http://php.net/manual/en/reflectionfunction.export.php ) * * Exports a Reflected function. * * @name mixed The reflection to export. * @ret mixed Setting to TRUE will return the export, as opposed * to emitting it. Setting to FALSE (the default) will * do the opposite. * * @return mixed If the return parameter is set to TRUE, then the * export is returned as a string, otherwise NULL is * returned. */ public static function export($name, $ret=false) { $obj = new self($name); $str = (string) $obj; if ($ret) { return $str; } print $str; } /** * ( excerpt from http://php.net/manual/en/reflectionfunction.invoke.php ) * * Invokes a reflected function. * * @return mixed Returns the result of the invoked function call. */ public function invoke(...$args) { if ($this->closure) { return hphp_invoke_method($this->closure, get_class($this->closure), '__invoke', $args); } return hphp_invoke($this->getName(), $args); } /** * ( excerpt from * http://php.net/manual/en/reflectionfunction.invokeargs.php ) * * Invokes the function and pass its arguments as array. * * @args mixed The passed arguments to the function as an array, * much like call_user_func_array() works. * * @return mixed Returns the result of the invoked function */ public function invokeArgs($args) { if ($this->closure) { return hphp_invoke_method($this->closure, get_class($this->closure), '__invoke', array_values($args)); } return hphp_invoke($this->getName(), array_values($args)); } /** * ( excerpt from * http://php.net/manual/en/reflectionfunction.isdisabled.php ) * * Checks if the function is disabled, via the disable_functions directive. * * @return bool TRUE if it's disable, otherwise FALSE */ public function isDisabled()[]: bool { // FIXME: HHVM doesn't support the disable_functions directive. return false; } <<__Native>> private function getClosureScopeClassname(object $closure)[]: ?string; <<__Pure, __MaybeMutable>> public function getClosureScopeClass(): ?ReflectionClass { if ($this->closure && ($cls = $this->getClosureScopeClassname($this->closure))) { return new ReflectionClass($cls); } return null; } <<__Native>> private function getClosureThisObject(object $closure): ?object; /** * Returns this pointer bound to closure. * * @return object|NULL Returns $this pointer. Returns NULL in case of * an error. */ public function getClosureThis(): mixed { if ($this->closure) { return $this->getClosureThisObject($this->closure); } return null; } use ReflectionTypedAttribute; } /** * ( excerpt from http://php.net/manual/en/class.reflectionmethod.php ) * * The ReflectionMethod class reports information about a method. */ class ReflectionMethod extends ReflectionFunctionAbstract { public string $name; // should be readonly (PHP compatibility) public string $class; // should be readonly (PHP compatibility) private /*string*/ $originalClass; private /*bool*/ $forcedAccessible = false; <<__Native>> private function __init(mixed $cls_or_obj, string $meth)[write_this_props]: bool; /** * ( excerpt from http://php.net/manual/en/reflectionmethod.construct.php ) * * Constructs a new ReflectionMethod. * * Format 1: * * @cls mixed Classname or object (instance of the class) that * contains the method. * @name string Name of the method. * * Format 2: * * @class_and_method string Class name and method, separated by :: */ public function __construct(...$args)[] { if (count($args) == 0 || count($args) > 2) { throw new Exception( 'ReflectionMethod::__construct() takes either 1 or 2 arguments'); } if (count($args) == 1) { $arr = explode('::', $args[0], 3); if (count($arr) !== 2) { $name = $args[0]; throw new ReflectionException((string)$name." is not a valid method name"); } list($cls, $name) = $arr; $classname = $cls; } else { $cls = $args[0]; $mth_names = explode('::', (string)$args[1]); $name = $mth_names[count($mth_names) - 1]; $classname = is_object($cls) ? get_class($cls) : $cls; $method = $args[1]; } $this->originalClass = $classname; if (!$this->__init($cls, (string) $name)) { throw new ReflectionException( "Method ".(string)$classname."::".(string)$name."() does not exist"); } $this->name = $this->getName(); $this->class = $this->getDeclaringClassname(); } /** * ( excerpt from http://php.net/manual/en/reflectionmethod.tostring.php ) * * @return string A string representation of this ReflectionMethod. */ public function __toString()[]: string { $preAttrs = varray[]; $decl_class = $this->getDeclaringClassname(); if ($this->originalClass !== $decl_class) { $preAttrs[] = "inherits $decl_class"; } else if ($proto_cls = $this->getPrototypeClassname()) { $preAttrs[] = interface_exists($proto_cls, false) ? 'implements '.$proto_cls : 'overrides '.$proto_cls; } if ($this->isConstructor()) { $preAttrs[] = 'ctor'; } $funcAttrs = varray[]; if ($this->isAbstract()) { $funcAttrs[] = 'abstract'; } if ($this->isFinal()) { $funcAttrs[] = 'final'; } if ($this->isStatic()) { $funcAttrs[] = 'static'; } if ($this->isPrivate()) { $funcAttrs[] = 'private'; } elseif ($this->isProtected()) { $funcAttrs[] = 'protected'; } else { $funcAttrs[] = 'public'; } return $this->__toStringHelper('Method', $preAttrs, $funcAttrs); } <<__Pure, __MaybeMutable>> public function __debugInfo() { return darray['name' => $this->name, 'class' => $this->class]; } /** * ( excerpt from http://php.net/manual/en/reflectionmethod.export.php ) * * Exports a ReflectionMethod. Warning: This function is currently not * documented; only its argument list is available. * * @cls mixed The class name. * @name mixed The name of the method. * @ret mixed Setting to TRUE will return the export, as opposed * to emitting it. Setting to FALSE (the default) will * do the opposite. * * @return ?string If the return parameter is set to TRUE, then the * export is returned as a string, otherwise NULL is * returned. */ public static function export( string $cls, string $name, bool $ret = false, ): ?string { $meth = new self($cls, $name); $str = (string) $meth; if ($ret) { return $str; } print $str; } <<__Pure, __MaybeMutable>> private function isAccessible(): bool { return $this->forcedAccessible || $this->isPublic(); } /** * ( excerpt from http://php.net/manual/en/reflectionmethod.invoke.php ) * * Invokes a reflected method. * * @obj mixed The object to invoke the method on. For static * methods, pass null to this parameter. * * @return mixed Returns the method result. */ public function invoke($obj, ...$args): mixed { $this->validateInvokeParameters($obj, $args); if ($this->isStaticInPrologue()) { // Docs says to pass null, but Zend completely ignores the argument $obj = null; } return hphp_invoke_method($obj, $this->originalClass, $this->getName(), $args); } /** * ( excerpt from http://php.net/manual/en/reflectionmethod.invokeargs.php * ) * * Invokes the reflected method and pass its arguments as array. * * @obj mixed The object to invoke the method on. In case of * static methods, you can pass null to this parameter. * @args mixed The parameters to be passed to the function, as an * array. * * @return mixed Returns the method result. */ public function invokeArgs($obj, $args): mixed { $this->validateInvokeParameters($obj, $args); if ($this->isStaticInPrologue()) { $obj = null; } return hphp_invoke_method($obj, $this->originalClass, $this->getName(), array_values($args)); } private function validateInvokeParameters($obj, $args): mixed { if (!$this->isAccessible()) { throw new ReflectionException( sprintf( 'Trying to invoke %s method %s::%s() from scope ReflectionMethod', ($this->isProtected() ? 'protected' : 'private'), $this->getDeclaringClassname(), $this->getName(), ) ); } if (!$this->isStaticInPrologue()) { if (!$obj) { $name = $this->originalClass.'::'.$this->getName(); throw new ReflectionException( "Trying to invoke non static method $name() without an object", ); } } } /** * ( excerpt from http://php.net/manual/en/reflectionmethod.isfinal.php ) * * Checks if the method is final. * * @return bool TRUE if the method is final, otherwise FALSE */ <<__Native>> public function isFinal()[]: bool; /** * ( excerpt from http://php.net/manual/en/reflectionmethod.isabstract.php * ) * * Checks if the method is abstract. * * @return bool TRUE if the method is abstract, otherwise FALSE */ <<__Native>> public function isAbstract()[]: bool; /** * ( excerpt from http://php.net/manual/en/reflectionmethod.ispublic.php ) * * Checks if the method is public. * * @return bool TRUE if the method is public, otherwise FALSE */ <<__Native>> public function isPublic()[]: bool; /** * ( excerpt from http://php.net/manual/en/reflectionmethod.isprotected.php * ) * * Checks if the method is protected. * * @return bool TRUE if the method is protected, otherwise FALSE */ <<__Native>> public function isProtected()[]: bool; /** * ( excerpt from http://php.net/manual/en/reflectionmethod.isprivate.php ) * * Checks if the method is private. Warning: This function is currently * not documented; only its argument list is available. * * @return bool TRUE if the method is private, otherwise FALSE */ <<__Native>> public function isPrivate()[]: bool; /** * ( excerpt from http://php.net/manual/en/reflectionmethod.isstatic.php ) * * Checks if the method is static. * * @return bool TRUE if the method is static, otherwise FALSE */ <<__Native>> public function isStatic()[]: bool; <<__Native>> private function isStaticInPrologue()[]: bool; /** * ( excerpt from * http://php.net/manual/en/reflectionmethod.isconstructor.php ) * * Checks if the method is a constructor. * * @return bool TRUE if the method is a constructor, otherwise FALSE */ <<__Native>> public function isConstructor()[]: bool; <<__Native>> public function isReadonly()[]: bool; /** * ( excerpt from * http://php.net/manual/en/reflectionmethod.getmodifiers.php ) * * Returns a bitfield of the access modifiers for this method. * * @return int A numeric representation of the modifiers. The * modifiers are listed below. The actual meanings of * these modifiers are described in the predefined * constants. */ <<__Native>> public function getModifiers()[]: int; /** * ( excerpt from * http://php.net/manual/en/reflectionmethod.getprototype.php ) * * Returns the methods prototype. * * @return object A ReflectionMethod instance of the method prototype. */ public function getPrototype()[]: ReflectionMethod { $proto_cls = $this->getPrototypeClassname(); $name = $this->getName(); if ($proto_cls) { return new ReflectionMethod($proto_cls, $name); } // This message is arguably misleading without $this->class throw new ReflectionException( sprintf('Method %s::%s does not have a prototype', $this->originalClass, $name,) ); } /** * ( excerpt from http://php.net/manual/en/reflectionmethod.getclosure.php * ) * * Warning: This function is currently not documented; only its argument * list is available. * * @object object Forbidden for static methods, required for other methods * * @return mixed Returns Closure. Returns NULL in case of an error. */ public function getClosure($object = null): ?Closure { if ($this->isStaticInPrologue()) { $object = null; } else { if (!$object) { trigger_error( 'ReflectionMethod::getClosure() expects parameter 1' . ' to be object, ' . gettype($object) . ' given', E_WARNING); return null; } $cls_name = $this->getDeclaringClassname(); if (!is_a($object, $cls_name)) { throw new ReflectionException( 'Given object is not an instance of the class this method was '. 'declared in' // mention declaringClassname / originalClass here ? ); } } return function (...$args) use ($object) { return $this->invokeArgs($object, $args); }; } /** * ( excerpt from * http://php.net/manual/en/reflectionmethod.setaccessible.php ) * * Sets a method to be accessible. For example, it may allow protected and * private methods to be invoked. * * @accessible mixed TRUE to allow accessibility, or FALSE. * * @return mixed No value is returned. */ public function setAccessible(bool $accessible)[write_props]: void { // Public methods are always accessible. Cannot manually set to not be // accessible. if ($this->isPublic()) { return; } $this->forcedAccessible = $accessible; } /** * ( excerpt from * http://php.net/manual/en/reflectionmethod.getdeclaringclass.php ) * * Gets the declaring class for the reflected method. * * @return ReflectionClass A ReflectionClass object of the class that the * reflected method is part of. */ public function getDeclaringClass()[] { return new ReflectionClass($this->getDeclaringClassname()); } public function getOriginalClassname()[]: string { return (string)$this->originalClass; } <<__Native>> private function getDeclaringClassname()[]: string; <<__Native>> private function getPrototypeClassname()[]: string; // ?string use ReflectionTypedAttribute; } /** * ( excerpt from http://php.net/manual/en/class.reflectionclass.php ) * * The ReflectionClass class reports information about a class. */ <<__NativeData('ReflectionClassHandle')>> class ReflectionClass implements Reflector { const int IS_IMPLICIT_ABSTRACT = 16; const int IS_EXPLICIT_ABSTRACT = 32; const int IS_FINAL = 64; public string $name; // should be readonly (PHP compatibility) private $obj = null; /** * ( excerpt from http://php.net/manual/en/reflectionclass.construct.php ) * * Constructs a new ReflectionClass object. Warning: This function is * currently not documented; only its argument list is available. * * @name mixed Either a string containing the name of the class to * reflect, or an object. */ public function __construct(mixed $name_or_obj)[] { if (is_object($name_or_obj)) { $this->obj = $name_or_obj; $classname = get_class($name_or_obj); } else { $classname = $name_or_obj; } $name = $this->__init($classname); if (!$name) { throw new ReflectionException("Class $classname does not exist"); } $this->name = $name; } <<__Native>> private function __init(string $name)[]: string; /** * ( excerpt from http://php.net/manual/en/reflectionclass.tostring.php ) * * @return string A string representation of this ReflectionClass. */ public function __toString()[]: string { $ret = ''; if ($docComment = $this->getDocComment()) { $ret .= $docComment . "\n"; } if ($this is ReflectionObject) { $ret .= 'Object of class [ '; } elseif ($this->isInterface()) { $ret .= 'Interface [ '; } elseif ($this->isTrait()) { $ret .= 'Trait [ '; } elseif ($this->isEnum()) { $ret .= 'Enum [ '; } else { $ret .= 'Class [ '; } if ($this->isInternal()) { $ret .= '<internal:'; if ($extensionName = $this->getExtensionName()) { $ret .= ':' . $extensionName; } $ret .= '> '; } else { $ret .= '<user> '; } if ($this->isIterateable()) { $ret .= '<iterable> '; } if ($this->isInterface()) { $ret .= 'interface '; } elseif ($this->isTrait()) { $ret .= 'trait '; } elseif ($this->isEnum()) { $ret .= 'enum '; } else { if ($this->isAbstract()) { $ret .= 'abstract '; } if ($this->isFinal()) { $ret .= 'final '; } $ret .= 'class '; } $ret .= $this->getName(); if ($parent = $this->getParentName()) { $ret .= " extends $parent"; } if ($ifaces = $this->getInterfaceNames()) { if ($this->isInterface()) { $ret .= ' extends '; } else { $ret .= ' implements '; } $ret .= implode(', ', $ifaces); } $ret .= " ] {\n"; if ((int)$this->getStartLine() > 0) { $file = (string)$this->getFileName(); $start = (string)$this->getStartLine(); $end = (string)$this->getEndLine(); $ret .= " @@ $file $start-$end\n"; } $consts = $this->getConstants(); $abs_consts = $this->getAbstractConstantNames(); $ret .= "\n - Constants [" . (count($consts) + count($abs_consts)) . "] {\n"; foreach ($consts as $k => $v) { $ret .= ' Constant [ ' . gettype($v) . " $k {" . (string)$v . "} ]\n"; } foreach ($abs_consts as $k) { $ret .= ' Abstract Constant [ '. $k ."]\n"; } $ret .= " }\n"; /* Static Properties */ $props = $this->getProperties(); $numStaticProps = 0; $numDynamicProps = 0; foreach ($props as $prop) { if ($prop->isStatic()) { ++$numStaticProps; } elseif (!$prop->isDefault()) { ++$numDynamicProps; } } $ret .= "\n - Static properties [{$numStaticProps}] {\n "; foreach ($props as $prop) { if (!$prop->isStatic()) { continue;} $ret .= ' ' . str_replace("\n", "\n ", (string)$prop); } $ret .= "}\n"; /* Static Methods */ $funcs = $this->getMethods(); $numStaticFuncs = 0; foreach ($funcs as $func) { if ($func->isStatic()) ++$numStaticFuncs; } $ret .= "\n - Static methods [{$numStaticFuncs}] {\n"; foreach ($funcs as $func) { if (!$func->isStatic()) continue; $ret .= ' ' . str_replace("\n", "\n ", rtrim((string)$func, "\n")) . "\n"; } $ret .= " }\n"; /* Declared Instance Properties */ $numMemberProps = count($props) - ($numStaticProps + $numDynamicProps); $ret .= "\n - Properties [{$numMemberProps}] {\n "; foreach ($props as $prop) { if ($prop->isStatic()) continue; if (!$prop->isDefault()) continue; $ret .= ' ' . str_replace("\n", "\n ", (string)$prop); } $ret .= "}\n"; /* Dynamic Instance Properties */ if ($numDynamicProps) { $ret .= "\n - Dynamic Properties [{$numDynamicProps}] {\n "; foreach ($props as $prop) { if ($prop->isStatic()) continue; if ($prop->isDefault()) continue; $ret .= ' ' . str_replace("\n", "\n ", (string)$prop); } $ret .= "}\n"; } /* Instance Methods */ $numMemberFuncs = count($funcs) - $numStaticFuncs; $ret .= "\n - Methods [{$numMemberFuncs}] {\n"; foreach ($funcs as $func) { if ($func->isStatic()) continue; $ret .= ' ' . str_replace("\n", "\n ", rtrim((string)$func, "\n")) . "\n"; } $ret .= " }\n"; $ret .= "}\n"; return preg_replace("/(^|\n)\s+(\n|$)/", "\n\n", $ret); } // Prevent cloning final public function __clone() { throw new BadMethodCallException( 'Trying to clone an uncloneable object of class ReflectionClass' ); } /** * ( excerpt from http://php.net/manual/en/reflectionclass.export.php ) * * Exports a reflected class. * * @name mixed The reflection to export. * @ret mixed Setting to TRUE will return the export, as opposed * to emitting it. Setting to FALSE (the default) will * do the opposite. * * @return mixed If the return parameter is set to TRUE, then the * export is returned as a string, otherwise NULL is * returned. */ public static function export($name, bool $ret=false): ?string { $obj = new ReflectionClass($name); $str = (string) $obj; if ($ret) { return $str; } print $str; } <<__Native>> public function getName()[]: string; <<__Native>> private function getParentName()[]: string; /** * ( excerpt from http://php.net/manual/en/reflectionclass.innamespace.php * ) * * Checks if this class is defined in a namespace. * * @return bool Returns TRUE on success or FALSE on failure. */ public function inNamespace()[]: bool { return strrpos($this->getName(), '\\') !== false; } /** * ( excerpt from * http://php.net/manual/en/reflectionclass.functionabstract.php ) * * Gets the namespace name. * * @return string The namespace name. */ public function getNamespaceName()[]: string { $name = $this->getName(); $pos = strrpos($name, '\\'); return ($pos === false) ? '' : substr($name, 0, $pos); } /** * ( excerpt from * http://php.net/manual/en/reflectionclass.getshortname.php ) * * Get the short name of the function (without the namespace part). * * @return string The short name of the function. */ public function getShortName()[]: string { $name = $this->getName(); $pos = strrpos($name, '\\'); return ($pos === false) ? $name : substr($name, $pos + 1); } <<__Native>> public function isHack()[]: bool; /** * ( excerpt from http://php.net/manual/en/reflectionclass.isinternal.php ) * * Checks if the class is defined internally by an extension, or the core, * as opposed to user-defined. * * @return bool Returns TRUE on success or FALSE on failure. */ <<__Native>> public function isInternal()[]: bool; public function isUserDefined()[]: bool { return !$this->isInternal(); } /** * ( excerpt from * http://php.net/manual/en/reflectionclass.isinstantiable.php ) * * Checks if the class is instantiable. * * @return bool Returns TRUE on success or FALSE on failure. */ <<__Native>> public function isInstantiable()[]: bool; /** * ( excerpt from * http://php.net/manual/en/reflectionclass.iscloneable.php ) * * Returns whether this class is cloneable. * * @return bool Returns TRUE if the class is cloneable, FALSE otherwise. */ public function isCloneable()[]: bool { return $this->isInstantiable() && (!$this->hasMethod('__clone') || $this->getMethod('__clone')->isPublic()); } /** * ( excerpt from http://php.net/manual/en/reflectionclass.getmethod.php ) * * Gets a ReflectionMethod for a class method. * * @name mixed The method name to reflect. * * @return mixed A ReflectionMethod. */ public function getMethod($name)[]: ReflectionMethod { return new ReflectionMethod($this->getName(), $name); } /** * ( excerpt from http://php.net/manual/en/reflectionclass.hasmethod.php ) * * Checks whether a specific method is defined in a class. * * @name mixed Name of the method being checked for. * * @return bool TRUE if it has the method, otherwise FALSE */ <<__Native>> public function hasMethod(string $name)[]: bool; /* Helper for getMethods: correctly ordered Set of the methods * declared on this class and its parents */ <<__Native>> private static function getMethodOrder(string $clsname, int $filter)[]: keyset; private function getMethodOrderWithCaching(?int $filter)[]: keyset<string> { if (null === $filter) { return self::getMethodOrderCache($this->getName()); } return self::getMethodOrder($this->getName(), $filter); } <<__Memoize>> private static function getMethodOrderCache( string $clsname, )[]: keyset<string> { return self::getMethodOrder($clsname, 0xFFFF); } /** * ( excerpt from http://php.net/manual/en/reflectionclass.getmethods.php ) * * Gets an array of methods for the class. * * @filter mixed Filter the results to include only methods with * certain attributes. Defaults to no filtering. * * Any combination of ReflectionMethod::IS_STATIC, * ReflectionMethod::IS_PUBLIC, * ReflectionMethod::IS_PROTECTED, * ReflectionMethod::IS_PRIVATE, * ReflectionMethod::IS_ABSTRACT, * ReflectionMethod::IS_FINAL. * * @return mixed An array of ReflectionMethod objects reflecting each * method. */ public function getMethods(?int $filter = null)[]: varray<ReflectionMethod> { $ret = varray[]; $clsname = $this->getName(); foreach ($this->getMethodOrderWithCaching($filter) as $name) { $ret[] = new ReflectionMethod($clsname, $name); } return $ret; } /** * ( excerpt from http://php.net/manual/en/reflectionclass.hasconstant.php * ) * * Checks whether the class has a specific constant defined or not. * * @name mixed The name of the constant being checked for. * * @return bool TRUE if the constant is defined, otherwise FALSE. */ <<__Native>> public function hasConstant(string $name)[]: bool; /** * ( excerpt from http://php.net/manual/en/reflectionclass.getconstant.php * ) * * Gets the defined constant. Warning: This function is currently not * documented; only its argument list is available. * * @name mixed Name of the constant. * * @return mixed Value of the constant, or FALSE if it doesn't exist */ <<__Native>> public function getConstant(string $name)[]: mixed; /** * ( excerpt from http://php.net/manual/en/reflectionclass.getconstants.php * ) * * Gets defined constants from a class. Warning: This function is * currently not documented; only its argument list is available. * * @return array An array of constants. Constant name in key, * constant value in value. */ public function getConstants()[]: darray<string, mixed> { return self::getConstantsCache($this->getName()); } <<__Memoize>> private static function getConstantsCache( string $clsname )[]: darray<string, mixed> { return self::getOrderedConstants($clsname); } /** * ( excerpt from * http://php.net/manual/en/reflectionclass.getabstractconstantnames.php * ) * * Returns an array containing the names of abstract constants as both * keys and values. * * @return array<string, string> */ public function getAbstractConstantNames()[]: darray<string, string> { return self::getAbstractConstantNamesCache($this->getName()); } <<__Memoize>> private static function getAbstractConstantNamesCache( string $clsname )[]: darray<string, string> { return self::getOrderedAbstractConstants($clsname); } private function getTypeConstantNamesWithCaching()[]: darray<string, string> { return self::getTypeConstantNamesCache($this->getName()); } <<__Memoize>> private static function getTypeConstantNamesCache( string $clsname )[]: darray<string, string> { return self::getOrderedTypeConstants($clsname); } public function getTypeConstant(string $name)[]: ReflectionTypeConstant { return new ReflectionTypeConstant($this->getName(), $name); } public function hasTypeConstant($name)[]: bool { return array_key_exists($name, $this->getTypeConstantNamesWithCaching()); } public function getTypeConstants()[]: varray<ReflectionTypeConstant> { $ret = varray[]; $class = $this->getName(); foreach ($this->getTypeConstantNamesWithCaching() as $name) { $ret[] = new ReflectionTypeConstant($class, $name); } return $ret; } <<__Native>> private static function getOrderedConstants( string $clsname )[]: darray<string, mixed>; <<__Native>> private static function getOrderedAbstractConstants( string $clsname )[]: darray<string, string>; <<__Native>> private static function getOrderedTypeConstants( string $clsname )[]: darray<string, string>; /** * ( excerpt from * http://php.net/manual/en/reflectionclass.getinterfacenames.php ) * * Get the interface names. * * @return mixed A numerical array with interface names as the * values. */ <<__Native>> public function getInterfaceNames()[]: varray<string>; /** * ( excerpt from * http://php.net/manual/en/reflectionclass.getinterfaces.php ) * * Gets the interfaces. * * @return mixed An associative array of interfaces, with keys as * interface names and the array values as * ReflectionClass objects. */ public function getInterfaces()[]: darray<string, ReflectionClass> { return $this->getReflectionClassesFromNames($this->getInterfaceNames()); } /** * Gets the list of implemented interfaces/inherited classes needed to * implement an interface / use a trait. Empty array for abstract and * concrete classes. */ <<__Native>> public function getRequirementNames()[]: varray<string>; /** * Gets ReflectionClass-es for the requirements of this class * * @return An associative array of requirements, with keys as * requirement names and the array values as ReflectionClass objects. */ public function getRequirements()[]: darray<string, ReflectionClass> { return $this->getReflectionClassesFromNames($this->getRequirementNames()); } /** * ( excerpt from * http://php.net/manual/en/reflectionclass.gettraitnames.php ) * * Warning: This function is currently not documented; only its argument * list is available. * * @return mixed Returns an array with trait names in values. Returns * NULL in case of an error. */ <<__Native>> public function getTraitNames()[]: varray<string>; /** * ( excerpt from * http://php.net/manual/en/reflectionclass.gettraitaliases.php ) * * Warning: This function is currently not documented; only its argument * list is available. * * @return mixed Returns an array with new method names in keys and * original names (in the format "TraitName::original") * in values. Returns NULL in case of an error. */ <<__Native>> public function getTraitAliases()[]: darray<string, string>; /** * ( excerpt from http://php.net/manual/en/reflectionclass.gettraits.php ) * * Warning: This function is currently not documented; only its argument * list is available. * * @return mixed Returns an array with trait names in keys and * instances of trait's ReflectionClass in values. * Returns NULL in case of an error. */ public function getTraits()[]: darray<string, ReflectionClass> { return $this->getReflectionClassesFromNames($this->getTraitNames()); } /** * Helper for the get{Traits,Interfaces,Requirements} methods */ private function getReflectionClassesFromNames( varray<string> $names )[]: darray<string, ReflectionClass> { $ret = darray[]; foreach ($names as $name) { $ret[$name] = new ReflectionClass($name); } return $ret; } /** * ( excerpt from http://php.net/manual/en/reflectionclass.isinterface.php * ) * * Checks whether the class is an interface. * * @return mixed Returns TRUE on success or FALSE on failure. */ <<__Native>> public function isInterface()[]: bool; /** * ( excerpt from http://php.net/manual/en/reflectionclass.isabstract.php ) * * Checks if the class is abstract. * * @return bool Returns TRUE on success or FALSE on failure. */ <<__Native>> public function isAbstract()[]: bool; /** * ( excerpt from http://php.net/manual/en/reflectionclass.isfinal.php ) * * Checks if a class is final. * * @return bool Returns TRUE on success or FALSE on failure. */ <<__Native>> public function isFinal()[]: bool; /** * ( excerpt from http://php.net/manual/en/reflectionclass.istrait.php ) * * Returns whether this is a trait. * * @return bool Returns TRUE if this is a trait, FALSE otherwise. */ <<__Native>> public function isTrait()[]: bool; /** * Returns whether this ReflectionClass represents an enum. * * @return bool Returns TRUE if this is an enum, FALSE otherwise. */ <<__Native>> public function isEnum()[]: bool; /** * Returns the underlying type of this ReflectionClass, given that it * represents an enum. If it does not, it throws. * * @return string the string representation of the underlying type. */ <<__Native>> public function getEnumUnderlyingType()[]: string; /** * ( excerpt from http://php.net/manual/en/reflectionclass.getmodifiers.php * ) * * Returns a bitfield of the access modifiers for this class. * * @return int Returns bitmask of modifier constants. */ <<__Native>> public function getModifiers()[]: int; /** * ( excerpt from http://php.net/manual/en/reflectionclass.isinstance.php ) * * Checks if an object is an instance of a class. * * @obj mixed The object being compared to. * * @return bool Returns TRUE on success or FALSE on failure. */ public function isInstance($obj)[]: bool { return is_a($obj, $this->getName()); } <<__Native>> private function getConstructorName()[]: string; /** * ( excerpt from * http://php.net/manual/en/reflectionclass.getconstructor.php ) * * Gets the constructor of the reflected class. * * @return mixed A ReflectionMethod object reflecting the class' * constructor, or NULL if the class has no * constructor. */ public function getConstructor()[]: ?ReflectionMethod { $constructor_name = $this->getConstructorName(); return $constructor_name ? $this->getMethod($constructor_name): null; } /** * ( excerpt from http://php.net/manual/en/reflectionclass.newinstance.php * ) * * Creates a new instance of the class. The given arguments are passed to * the class constructor. */ public function newInstance(...$args) { if ($args && !$this->getConstructorName()) { // consistent with reference, but perhaps not particularly useful throw new ReflectionException( 'Class '.$this->getName().' lacks a constructor, so you cannot pass' .' any constructor arguments' ); } return hphp_create_object($this->getName(), $args); } /** * ( excerpt from * http://php.net/manual/en/reflectionclass.newinstanceargs.php ) * * Creates a new instance of the class, the given arguments are passed to * the class constructor. * * @args mixed The parameters to be passed to the class constructor * as an array. * * @return mixed Returns a new instance of the class. */ public function newInstanceArgs(Traversable<mixed> $args = varray[])[defaults] { if ($args && !$this->getConstructorName()) { // consistent with reference, but perhaps not particularly useful throw new ReflectionException( 'Class '.$this->getName().' lacks a constructor, so you cannot pass' .' any constructor arguments' ); } return hphp_create_object($this->getName(), varray($args)); } /** * ( excerpt from * http://php.net/manual/en/reflectionclass.newinstancewithoutconstructor.php * ) * * Creates a new instance of the class without invoking the constructor. */ public function newInstanceWithoutConstructor()[] { return hphp_create_object_without_constructor($this->getName()); } // This calculations requires walking the preclasses in the hierarchy and // should not be getting performed repeatedly. <<__Native>> // returns dict: // 'properties' => darray<string, prop_info_array> // 'private_properties' => darray<string, prop_info_array> // 'properties_index' => darray<string, int> // 'private_properties_index' => darray<string, int> private static function getClassPropertyInfo(string $clsname)[]: dict; <<__Native>> private function getDynamicPropertyInfos(object $obj)[]: dict<string, mixed>; private function getOrderedPropertyInfos()[]: ConstMap<string, mixed> { $props_map = self::getPropsMapCache($this->getName()); if (!$this->obj) { return $props_map; } // caching cannot be well applied to an object's dynamic properties, // since they can be added and removed at any time between calls to // property methods. $dynamic_props = $this->getDynamicPropertyInfos($this->obj); return (!$dynamic_props) ? $props_map : new Map(HH\Lib\Dict\merge($props_map, $dynamic_props)); } <<__Memoize>> private static function getPropsMapCache( string $clsname )[]: ImmMap<string, mixed> { return new ImmMap(self::getClassPropertyInfo($clsname)); } /** * ( excerpt from http://php.net/manual/en/reflectionclass.getproperty.php * ) * * Gets a ReflectionProperty for a class's property. * * @name mixed The property name. * * @return mixed A ReflectionProperty. */ public function getProperty($name)[] { $class = $this->name; if (!$this->hasProperty($name)) { throw new ReflectionException("Property $class::$name does not exist"); } if ($this->obj) { return new ReflectionProperty($this->obj, $name); } else { return new ReflectionProperty($this->name, $name); } } /** * ( excerpt from http://php.net/manual/en/reflectionclass.hasproperty.php * ) * * Checks whether the specified property is defined. * * @name mixed Name of the property being checked for. * * @return bool TRUE if it has the property, otherwise FALSE */ public function hasProperty($name)[]: bool { return $this->getOrderedPropertyInfos()->containsKey($name); } /** * ( excerpt* http://php.net/manual/en/reflectionclass.getproperties.php ) * * Retrieves reflected properties. * * @filter mixed The optional filter, for filtering desired property * types. It's configured using the ReflectionProperty * constants, and defaults to all property types. * * @return mixed An array of ReflectionProperty objects. */ public function getProperties($filter = 0xFFFF)[]: varray<ReflectionProperty> { $ret = varray[]; foreach ($this->getOrderedPropertyInfos() as $name => $prop_info) { if ($this->obj) { $p = new ReflectionProperty($this->obj, $name); } else { $p = new ReflectionProperty($this->name, $name); } if (($filter & ReflectionProperty::IS_PUBLIC) && $p->isPublic() || ($filter & ReflectionProperty::IS_PROTECTED) && $p->isProtected() || ($filter & ReflectionProperty::IS_PRIVATE) && $p->isPrivate() || ($filter & ReflectionProperty::IS_STATIC) && $p->isStatic()) { $ret[] = $p; } } return $ret; } /** * ( excerpt from * http://php.net/manual/en/reflectionclass.getstaticproperties.php ) * * Get the static properties. Warning: This function is currently not * documented; only its argument list is available. * * @return mixed The static properties, as an array. */ public function getStaticProperties(): darray<string, mixed> { $ret = darray[]; foreach ($this->getProperties(ReflectionProperty::IS_STATIC) as $prop) { $val = hphp_get_static_property($this->getName(), $prop->name, true); $ret[$prop->name] = $val; } return $ret; } /** * ( excerpt from * http://php.net/manual/en/reflectionclass.getstaticpropertyvalue.php ) * * Gets the value of a static property on this class. * * @name mixed The name of the static property for which to return * a value. * @default mixed * * @return mixed The value of the static property. */ public function getStaticPropertyValue($name, ...$args) { // We can't check if a parameter isn't passed, // we can only check its default value, but that fails // if I want to pass the default value. // Use variadic args for this. if ($this->hasProperty($name) && $this->getProperty($name)->isStatic()) { return hphp_get_static_property($this->getName(), $name, false); } else if (!array_key_exists(0, $args)) { throw new ReflectionException( sprintf("Class %s does not have a property named %s", $this->getName(), $name) ); } return $args[0]; } /** * ( excerpt from * http://php.net/manual/en/reflectionclass.setstaticpropertyvalue.php ) * * Sets static property value. Warning: This function is currently not * documented; only its argument list is available. * * @name mixed Property name. * @value mixed New property value. */ public function setStaticPropertyValue($name, $value): void { // XXX: should be __Native, not a builtin hphp_set_static_property($this->getName(), $name, $value, false); } /** * ( excerpt from * http://php.net/manual/en/reflectionclass.getdefaultproperties.php ) * * Gets default properties from a class (including inherited properties). * * This method only works for static properties when the default value is * known statically. If it is not known statically you will get null instead * of the correct value. Do not rely on this API for default values of * static properties. * * @return mixed An array of default properties, with the key being * the name of the property and the value being the * default value of the property or NULL if the * property doesn't have a default value. The function * does not distinguish between static and non static * properties and does not take visibility modifiers * into account. */ public function getDefaultProperties()[]: darray<string, mixed> { $ret = darray[]; foreach ($this->getProperties() as $prop) { if ($prop->isDefault()) { $ret[$prop->name] = $prop->getDefaultValue(); } } return $ret; } /** * ( excerpt from http://php.net/manual/en/reflectionclass.getextension.php * ) * * Gets a ReflectionExtension object for the extension which defined the * class. * * @return mixed A ReflectionExtension object representing the * extension which defined the class, or NULL for * user-defined classes. */ public function getExtension()[]: ?ReflectionExtension { // FIXME: HHVM doesn't support extension info return new ReflectionExtension($this->getExtensionName()); // Truthful implementation would be: // return null; // A serious implementation would be: // return new ReflectionExtension($this->getExtensionName()); } /** * ( excerpt from * http://php.net/manual/en/reflectionclass.getextensionname.php ) * * Gets the name of the extension which defined the class. * * @return mixed The name of the extension which defined the class, * or FALSE for user-defined classes. */ public function getExtensionName()[]: mixed { // FIXME: HHVM doesn't support extension info return ''; // Truthful implementation would be: // return false; // A serious implementation would have this function __Native } /** * ( excerpt from * http://php.net/manual/en/reflectionclass.isiterateable.php ) * * Checks whether the class is iterateable. * * @return bool Returns TRUE on success or FALSE on failure. */ public function isIterateable()[]: bool { return $this->isSubclassOf(\HH\Traversable::class); } /** * ( excerpt from * http://php.net/manual/en/reflectionclass.implementsinterface.php ) * * Checks whether it implements an interface. * * @cls mixed The interface name. * * @return bool Returns TRUE on success or FALSE on failure. */ public function implementsInterface($cls)[]: bool { if ($cls is ReflectionClass) { $cls = $cls->getName(); } // Normalize to avoid autoloading twice for undefined classes $normalized_cls = $cls[0] == '\\' ? substr($cls, 1) : $cls; if (!interface_exists($normalized_cls)) { throw new ReflectionException("Interface $normalized_cls does not exist"); } return $this->isInterface() ? is_a($this->getName(), $normalized_cls, true) : $this->isSubclassOf($normalized_cls); } /** * ( excerpt from * http://php.net/manual/en/reflectionclass.getparentclass.php ) * * Warning: This function is currently not documented; only its argument * list is available. * * @return mixed A ReflectionClass, or false. */ public function getParentClass()[]: mixed { $parent = $this->getParentName(); return $parent ? new ReflectionClass($parent) : false; } /** * ( excerpt from http://php.net/manual/en/reflectionclass.issubclassof.php * ) * * Checks if the class is a subclass of a specified class or implements a * specified interface. * * @cls mixed The class name being checked against. * * @return bool Returns TRUE on success or FALSE on failure. */ public function isSubclassOf($cls)[]: bool { if ($cls is ReflectionClass) { $cls = $cls->getName(); } return is_subclass_of($this->getName(), $cls); } /** * ( excerpt from http://php.net/manual/en/reflectionclass.getfilename.php * ) * * Gets the filename of the file in which the class has been defined. * * @return mixed Returns the filename of the file in which the class * has been defined. If the class is defined in the PHP * core or in a PHP extension, FALSE is returned. */ <<__Native>> public function getFileName()[]: mixed; /** * Gets the declaring file for the reflected class. * * @return ReflectionFile A ReflectionFile object of the file that the * reflected class is part of. */ public function getFile()[]: ReflectionFile { $fileName = $this->getFileName(); if ($fileName === false) { throw new ReflectionException( 'Couldn\'t get ReflectionFile because the class was not defined in a '. 'file.' ); } if (!is_string($fileName)) { throw new ReflectionException( 'Unexpected non-string file name for ReflectionClass.' ); } return new ReflectionFile((string)$fileName); } /** * ( excerpt from http://php.net/manual/en/reflectionclass.getstartline.php * ) * * Get the starting line number. Warning: This function is currently not * documented; only its argument list is available. * * @return int The starting line number, as an integer. */ <<__Native>> public function getStartLine()[]: mixed; /** * ( excerpt from http://php.net/manual/en/reflectionclass.getendline.php ) * * Gets end line number from a user-defined class definition. * * @return int The ending line number of the user defined class, or * FALSE if unknown. */ <<__Native>> public function getEndLine()[]: mixed; /** * ( excerpt from * http://php.net/manual/en/reflectionclass.getdoccomment.php ) * * Gets doc comments from a class. Warning: This function is currently not * documented; only its argument list is available. * * @return mixed The doc comment if it exists, otherwise FALSE */ <<__Native>> public function getDocComment()[]: mixed; use ReflectionTypedAttribute; <<__Native>> public function getAttributesNamespaced()[]: darray<string, varray<mixed>>; use ReflectionLegacyAttribute; <<__Native>> public function getAttributesRecursiveNamespaced( ): darray<string, varray<mixed>>; <<__Native>> public function getReifiedTypeParamInfo()[]: varray; } /////////////////////////////////////////////////////////////////////////////// // object /** * ( excerpt from http://php.net/manual/en/class.reflectionobject.php ) * * The ReflectionObject class reports information about an object. * */ class ReflectionObject extends ReflectionClass { /** * ( excerpt from http://php.net/manual/en/reflectionobject.construct.php * ) * * Constructs a ReflectionObject. */ <<__Pure>> public function __construct($argument) { if (!is_object($argument)) { throw new ReflectionException( __CLASS__.' expects to be constructed with an object, got ' .gettype($argument) ); } parent::__construct($argument); } /** * ( excerpt from http://php.net/manual/en/reflectionobject.export.php ) * * Exports a reflection. Warning: This function is currently not * documented; only its argument list is available. * * @obj mixed The reflection to export. * @ret mixed Setting to TRUE will return the export, as opposed * to emitting it. Setting to FALSE (the default) will * do the opposite. * * @return mixed If the return parameter is set to TRUE, then the * export is returned as a string, otherwise NULL is * returned. */ public static function export($obj, $ret=false) { $obj = new ReflectionObject($obj); $str = (string)$obj; if ($ret) { return $str; } print $str; } } /////////////////////////////////////////////////////////////////////////////// // type constant /** * The ReflectionTypeConstant class reports information about an object. * */ <<__NativeData('ReflectionConstHandle')>> class ReflectionTypeConstant implements Reflector { /** * Constructs a new ReflectionTypeConstant. * * @cls mixed Classname or object (instance of the class) that * contains the type constant. * @name string Name of the type constant. */ public function __construct(mixed $cls, string $name)[] { if (!$this->__init($cls, (string) $name)) { $classname = is_object($cls) ? get_class($cls) : $cls; throw new ReflectionException( "Type Constant $classname::$name does not exist"); } } /** * Get the name of the type constant. * * @return string The name of the type constant. */ <<__Native>> public function getName()[]: string; /** * Checks if the type constant is abstract * * @return bool Returns TRUE on success or FALSE on failure. */ <<__Native>> public function isAbstract()[]: bool; /** * Get the type assigned to this type constant as a string * * @return NULL | string The assigned type or null if is abstract */ public function getAssignedTypeText()[]: ?string { return $this->getAssignedTypeHint() ?: null; } /** * Gets the declaring class for the reflected type constant. This is * the most derived class in which the type constant is declared. * * @return ReflectionClass A ReflectionClass object of the class that the * reflected type constant is part of. */ public function getDeclaringClass()[] { return new ReflectionClass($this->getDeclaringClassname()); } /** * Gets the class for the reflected type constant. * * @return ReflectionClass A ReflectionClass object of the class that the * reflected type constant is part of. */ public function getClass()[] { return new ReflectionClass($this->getClassname()); } public function __toString()[] { $abstract = $this->isAbstract() ? 'abstract ' : ''; $type_text = $this->getAssignedTypeText() ?? ''; $val = $this->isAbstract() ? '' : " = $type_text"; return "TypeConstant [ {$abstract}const type {$this->getName()}{$val}]\n"; } // Prevent cloning final public function __clone() { throw new BadMethodCallException( 'Trying to clone an uncloneable object of class ReflectionTypeConstant' ); } public static function export($cls, $name, $ret=false) { $obj = new self($cls, $name); $str = (string)$obj; if ($ret) { return $str; } print $str; } <<__Native>> private function __init(mixed $cls_or_obj, string $const)[]: bool; <<__Native>> private function getAssignedTypeHint()[]: string; <<__Native>> private function getDeclaringClassname()[]: string; <<__Native>> private function getClassname()[]: string; /* returns the shape containing the full type information for this * type constant. The structure of this shape is specified in * reflection.hhi. */ public function getTypeStructure()[] { return HH\type_structure( $this->getClassname(), $this->getName() ); } } /////////////////////////////////////////////////////////////////////////////// // type aliases /** The ReflectionTypeAlias class reports information about a type * alias. */ <<__NativeData('ReflectionTypeAliasHandle')>> class ReflectionTypeAlias implements Reflector { private string $name = ''; /** * Constructs a new ReflectionTypeAlias. * * @name string Name of the type alias. */ final public function __construct(string $name)[] { $n = $this->__init($name); if (!$n) { throw new ReflectionException( "type alias {$name} does not exist"); } $this->name = $n; } // helper for ctor <<__Native>> private function __init(string $name)[write_this_props]: string; /** * Get the TypeStructure that contains the full type information of * the assigned type. * * @return array The type structure of the type alias. */ <<__Native>> public function getTypeStructure()[]: darray; /** * Gets all attributes * * @return darray<arraykey, varray<mixed>> */ <<__Native>> final public function getAttributesNamespaced( )[]: darray<arraykey, varray<mixed>>; use ReflectionLegacyAttribute; use ReflectionTypedAttribute; /** * Get the TypeStructure with type information resolved. Call at * your own peril as non-hoisted classes might cause fatal. * * @return array The resolved type structure of the type alias. */ public function getResolvedTypeStructure()[] { return HH\type_structure($this->name); } /** * Get the assigned type as a string. * * @return string The assigned type. */ <<__Native>> public function getAssignedTypeText()[]: string; /** * Get the name of the type alias. * * @return string The name of the type alias */ public function getName()[] { return $this->name; } /** * Get the name of the file in which the type alias was defined. */ <<__Native>> public function getFileName()[]: string; /** * Gets the declaring file for the reflected type alias. * * @return ReflectionFile A ReflectionFile object of the file that the * reflected type alias is part of. */ public function getFile()[] { return new ReflectionFile($this->getFileName()); } // Prevent cloning final public function __clone() { throw new BadMethodCallException( 'Trying to clone an uncloneable object of class ReflectionTypeAlias' ); } public function __toString()[] { return "TypeAlias [ {$this->name} : {$this->getAssignedTypeText()} ]\n"; } } /////////////////////////////////////////////////////////////////////////////// // files /** The ReflectionFile class reports information about a file. */ <<__NativeData('ReflectionFileHandle')>> final class ReflectionFile implements Reflector { private string $name = ''; /** * Constructs a new ReflectionFile. * * @name string Name of the file. */ final public function __construct(string $name)[] { $n = $this->__init($name); if (!$n) { throw new ReflectionException( "file {$name} does not exist"); } $this->name = $n; } // helper for ctor <<__Native>> private function __init(string $name)[]: string; /** * Gets all attributes * * @return darray<arraykey, varray<mixed>> */ <<__Native>> final public function getAttributesNamespaced( )[]: darray<arraykey, varray<mixed>>; use ReflectionLegacyAttribute; use ReflectionTypedAttribute; /** * Get the name of the file. * * @return string The name of the file */ public function getName()[] { return $this->name; } // Prevent cloning final public function __clone() { throw new BadMethodCallException( 'Trying to clone an uncloneable object of class ReflectionFile' ); } public function __toString()[] { return "File [ {$this->name} ]\n"; } }