/** Create string representation */ public function toString() : string { $args = []; if (isset($this->args)) { foreach ($this->args as $arg) { if (is_array($arg)) { $args[] = 'array[' . sizeof($arg) . ']'; } else { if ($arg instanceof \Closure) { $args[] = \xp::stringOf($arg); } else { if (is_object($arg)) { $args[] = nameof($arg) . '{}'; } else { if (is_string($arg)) { $display = str_replace('%', '%%', addcslashes(substr($arg, 0, min(false === ($p = strpos($arg, "\n")) ? 0x40 : $p, 0x40)), "..")); $args[] = '(0x' . dechex(strlen($arg)) . ")'" . $display . "'"; } else { if (null === $arg) { $args[] = 'NULL'; } else { if (is_scalar($arg)) { $args[] = (string) $arg; } else { if (is_resource($arg)) { $args[] = (string) $arg; } else { $args[] = '<' . gettype($arg) . '>'; } } } } } } } } } return sprintf(" at %s::%s(%s) [line %d of %s] %s\n", isset($this->class) ? XPClass::nameOf($this->class) : '<main>', $this->method ?? '<main>', implode(', ', $args), $this->line, basename($this->file ?? __FILE__), $this->message); }
/** * 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); } }
/** * Changes the value of the field represented by this Field, on the * specified object. * * @param object instance * @param var value * @throws lang.IllegalArgumentException in case the passed object is not an instance of the declaring class * @throws lang.IllegalAccessException in case this field is not public */ public function set($instance, $value) { if (null !== $instance && !$instance instanceof $this->_class) { throw new IllegalArgumentException(sprintf('Passed argument is not a %s class (%s)', XPClass::nameOf($this->_class), \xp::typeOf($instance))); } // Check modifiers. If scope is an instance of this class, allow // protected method invocation (which the PHP reflection API does // not). $m = $this->_reflect->getModifiers(); $public = $m & MODIFIER_PUBLIC; if (!$public && !$this->accessible) { $t = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1); $scope = $t[1]['class'] ?? \lang\ClassLoader::getDefault()->loadUri($t[0]['file'])->literal(); $decl = $this->_reflect->getDeclaringClass()->getName(); if ($m & MODIFIER_PROTECTED) { $allow = $scope === $decl || is_subclass_of($scope, $decl); } else { $allow = $scope === $decl; } if (!$allow) { throw new IllegalAccessException(sprintf('Cannot write %s %s::$%s from scope %s', Modifiers::stringOf($this->getModifiers()), XPClass::nameOf($this->_class), $this->_reflect->getName(), $scope)); } } try { $public || $this->_reflect->setAccessible(true); $this->_reflect->setValue($instance, $value); } catch (\lang\Throwable $e) { throw $e; } catch (\Throwable $e) { throw new \lang\XPException($e->getMessage()); } }
/** Retrieve return type name */ public function getReturnTypeName() : string { return XPClass::nameOf($this->_class); }