/** 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);
 }
Exemple #2
0
 /**
  * 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);
     }
 }
Exemple #3
0
 /**
  * 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);
 }