/** * Invokes the underlying method represented by this Method object, * on the specified object with the specified parameters. * * Example: * <code> * $method= XPClass::forName('lang.Object')->getMethod('toString'); * * var_dump($method->invoke(new Object())); * </code> * * Example (passing arguments) * <code> * $method= XPClass::forName('lang.types.String')->getMethod('concat'); * * var_dump($method->invoke(new String('Hello'), array('World'))); * </code> * * Example (static invokation): * <code> * $method= XPClass::forName('util.log.Logger')->getMethod('getInstance'); * * var_dump($method->invoke(NULL)); * </code> * * @param lang.Object obj * @param var[] args default array() * @return var * @throws lang.IllegalArgumentException in case the passed object is not an instance of the declaring class * @throws lang.IllegalAccessException in case the method is not public or if it is abstract * @throws lang.reflect.TargetInvocationException for any exception raised from the invoked method */ public function invoke($obj, $args = array()) { if (NULL !== $obj && !$obj instanceof $this->_class) { throw new IllegalArgumentException(sprintf('Passed argument is not a %s class (%s)', xp::nameOf($this->_class), xp::typeOf($obj))); } // Check modifiers. If caller is an instance of this class, allow // protected method invocation (which the PHP reflection API does // not). $m = $this->_reflect->getModifiers(); if ($m & MODIFIER_ABSTRACT) { throw new IllegalAccessException(sprintf('Cannot invoke abstract %s::%s', $this->_class, $this->_reflect->getName())); } $public = $m & MODIFIER_PUBLIC; if (!$public && !$this->accessible) { $t = debug_backtrace(0); $decl = $this->_reflect->getDeclaringClass()->getName(); if ($m & MODIFIER_PROTECTED) { $allow = $t[1]['class'] === $decl || is_subclass_of($t[1]['class'], $decl); } else { $allow = $t[1]['class'] === $decl && self::$SETACCESSIBLE_AVAILABLE; } if (!$allow) { throw new IllegalAccessException(sprintf('Cannot invoke %s %s::%s from scope %s', Modifiers::stringOf($this->getModifiers()), $this->_class, $this->_reflect->getName(), $t[1]['class'])); } } // For non-public methods: Use setAccessible() / invokeArgs() combination // if possible, resort to __call() workaround. try { if ($public) { return $this->_reflect->invokeArgs($obj, (array) $args); } if (self::$SETACCESSIBLE_AVAILABLE) { $this->_reflect->setAccessible(TRUE); return $this->_reflect->invokeArgs($obj, (array) $args); } else { if ($m & MODIFIER_STATIC) { return call_user_func(array($this->_class, '__callStatic'), "" . $this->_reflect->getName(), $args); } else { return $obj->__call("" . $this->_reflect->getName(), $args); } } } catch (SystemExit $e) { throw $e; } catch (Throwable $e) { throw new TargetInvocationException($this->_class . '::' . $this->_reflect->getName(), $e); } catch (Exception $e) { throw new TargetInvocationException($this->_class . '::' . $this->_reflect->getName(), new XPException($e->getMessage())); } }
/** * Uses the constructor represented by this Constructor object to create * and initialize a new instance of the constructor's declaring class, * with the specified initialization parameters. * * Example: * <code> * $constructor= XPClass::forName('util.Binford')->getConstructor(); * * $instance= $constructor->newInstance(); * $instance= $constructor->newInstance(array(6100)); * </code> * * @param var[] args * @return lang.Generic * @throws lang.IllegalAccessException in case the constructor is not public or if it is abstract * @throws lang.reflect.TargetInvocationException in case the constructor throws an exception */ public function newInstance(array $args = array()) { // Check whether class is abstract $class = new ReflectionClass($this->_class); if ($class->isAbstract()) { throw new IllegalAccessException('Cannot instantiate abstract class ' . $this->_class); } // Check modifiers. If caller is an instance of this class, allow private and // protected constructor invocation (which the PHP reflection API does not). $m = $this->_reflect->getModifiers(); $public = $m & MODIFIER_PUBLIC; if (!$public && !$this->accessible) { $t = debug_backtrace(0); $decl = $this->_reflect->getDeclaringClass()->getName(); if ($m & MODIFIER_PROTECTED) { $allow = $t[1]['class'] === $decl || is_subclass_of($t[1]['class'], $decl); } else { $allow = $t[1]['class'] === $decl && self::$SETACCESSIBLE_AVAILABLE; } if (!$allow) { throw new IllegalAccessException(sprintf('Cannot invoke %s constructor of class %s from scope %s', Modifiers::stringOf($this->getModifiers()), $this->_class, $t[1]['class'])); } } // For non-public constructors: Use setAccessible() / invokeArgs() combination // if possible, resort to __call() workaround. try { if ($public) { return $class->newInstanceArgs($args); } $instance = unserialize('O:' . strlen($this->_class) . ':"' . $this->_class . '":0:{}'); if (self::$SETACCESSIBLE_AVAILABLE) { $this->_reflect->setAccessible(TRUE); $this->_reflect->invokeArgs($instance, $args); } else { $instance->__call("__construct", $args); } return $instance; } catch (SystemExit $e) { throw $e; } catch (Throwable $e) { throw new TargetInvocationException($this->_class . '::<init>', $e); } catch (Exception $e) { throw new TargetInvocationException($this->_class . '::<init>', new XPException($e->getMessage())); } }
/** * Invokes the underlying method represented by this Method object, * on the specified object with the specified parameters. * * Example: * ```php * $method= XPClass::forName('lang.Object')->getMethod('toString'); * $str= $method->invoke(new Object()); * ``` * * Example (passing arguments) * ```php * $method= XPClass::forName('util.Date')->getMethod('format'); * $str= $method->invoke(Date::now(), ['%d.%m.%Y']); * ``` * * Example (static invokation): * ```php * $method= XPClass::forName('util.log.Logger')->getMethod('getInstance'); * $log= $method->invoke(null); * ``` * * @param object $obj * @param var[] $args default [] * @return var * @throws lang.IllegalArgumentException in case the passed object is not an instance of the declaring class * @throws lang.IllegalAccessException in case the method is not public or if it is abstract * @throws lang.reflect.TargetInvocationException for any exception raised from the invoked method */ public function invoke($obj, $args = []) { if (null !== $obj && !$obj instanceof $this->_class) { throw new IllegalArgumentException(sprintf('Passed argument is not a %s class (%s)', XPClass::nameOf($this->_class), \xp::typeOf($obj))); } // Check modifiers. If caller is an instance of this class, allow // protected method invocation (which the PHP reflection API does // not). $m = $this->_reflect->getModifiers(); if ($m & MODIFIER_ABSTRACT) { throw new IllegalAccessException(sprintf('Cannot invoke abstract %s::%s', XPClass::nameOf($this->_class), $this->_reflect->getName())); } $public = $m & MODIFIER_PUBLIC; if (!$public && !$this->accessible) { $t = debug_backtrace(0, 2); $decl = $this->_reflect->getDeclaringClass()->getName(); if ($m & MODIFIER_PROTECTED) { $allow = $t[1]['class'] === $decl || is_subclass_of($t[1]['class'], $decl); } else { $allow = $t[1]['class'] === $decl; } if (!$allow) { throw new IllegalAccessException(sprintf('Cannot invoke %s %s::%s from scope %s', Modifiers::stringOf($this->getModifiers()), XPClass::nameOf($this->_class), $this->_reflect->getName(), $t[1]['class'])); } } try { if (!$public) { $this->_reflect->setAccessible(true); } return $this->_reflect->invokeArgs($obj, (array) $args); } catch (\lang\SystemExit $e) { throw $e; } catch (\Throwable $e) { throw new TargetInvocationException(XPClass::nameOf($this->_class) . '::' . $this->_reflect->getName(), $e); } }
/** Retrieve string representation */ public function toString() : string { $signature = ''; foreach ($this->getParameters() as $param) { if ($param->isOptional()) { $signature .= ', [' . $param->getTypeName() . ' $' . $param->getName() . '= ' . str_replace("\n", ' ', \xp::stringOf($param->getDefaultValue())) . ']'; } else { $signature .= ', ' . $param->getTypeName() . ' $' . $param->getName(); } } if ($exceptions = $this->getExceptionNames()) { $throws = ' throws ' . implode(', ', $exceptions); } else { $throws = ''; } return sprintf('%s %s %s(%s)%s', Modifiers::stringOf($this->getModifiers()), $this->getReturnTypeName(), $this->getName(), substr($signature, 2), $throws); }
public function staticModifier() { $this->assertTrue(Modifiers::isStatic(MODIFIER_STATIC)); $this->assertEquals('public static', Modifiers::stringOf(MODIFIER_STATIC)); }
/** Creates a string representation of this field */ public function toString() : string { return sprintf('%s %s %s::$%s', Modifiers::stringOf($this->getModifiers()), $this->getTypeName(), $this->getDeclaringClass()->getName(), $this->getName()); }