public function newType($type, $name) { if (FALSE === ($p = strrpos($name, "."))) { $class = $name; $ns = ""; } else { $class = substr($name, $p + 1); $ns = "namespace " . strtr(substr($name, 0, $p), ".", "\\") . ";"; } \lang\DynamicClassLoader::instanceFor("test")->setClassBytes($name, sprintf("%s %s %s extends \\lang\\Object { }", $ns, $type, $class)); }
/** * Helper method for defineClass() and defineInterface(). * * @param string $spec * @param [:var] $declaration * @param var $def * @return lang.XPClass */ public static function defineType($spec, $declaration, $def) { if ('#' === $spec[0]) { $p = strrpos($spec, ' '); $typeAnnotations = substr($spec, 0, $p) . "\n"; $spec = substr($spec, $p + 1); } else { $typeAnnotations = ''; } if (isset(\xp::$cl[$spec])) { return new XPClass(literal($spec)); } // Backwards compatibility, deprecated usage via declaration inside string. if (!is_array($declaration)) { preg_match('/(class|interface|trait)\\s+([^ ]+)(\\s+extends\\s+([^ ]+))?(\\s+implements\\s+([^\\{]+))?/', $declaration, $parsed); $declaration = ['kind' => $parsed[1], 'use' => [], 'extends' => [], 'implements' => []]; if (isset($parsed[4])) { foreach (explode(',', $parsed[4]) as $type) { $declaration['extends'][] = trim($type, ' '); } } if (isset($parsed[6])) { foreach (explode(',', $parsed[6]) as $type) { $declaration['implements'][] = trim($type, ' '); } } } $functions = []; if (is_array($def)) { $iface = 'interface' === $declaration['kind']; $bytes = ''; foreach ($def as $name => $member) { if ('#' === $name[0]) { $p = strrpos($name, ' '); $memberAnnotations = substr($name, 0, $p) . "\n"; $name = substr($name, $p + 1); } else { $memberAnnotations = ''; } if ($member instanceof \Closure) { $bytes .= $memberAnnotations . self::defineForward($name, (new \ReflectionFunction($member))->getParameters(), $iface ? null : 'return self::$__func["' . $name . '"]->__invoke(%s);'); $iface || ($functions[$name] = $member); } else { $bytes .= $memberAnnotations . 'public $' . $name . '= ' . var_export($member, true) . ';'; } } if ($iface) { // Don't handle constructors } else { if (isset($functions['__construct'])) { $bytes = 'static $__func= []; ' . $bytes; } else { if ($declaration['extends'] && ($ctor = (new \ReflectionClass(self::classLiteral($declaration['extends'][0])))->getConstructor())) { $constructor = self::defineForward('__construct', $ctor->getParameters(), 'parent::__construct(%s);'); } else { $constructor = self::defineForward('__construct', [], ''); foreach ($declaration['use'] as $use) { $trait = self::classLiteral($use); if ($ctor = (new \ReflectionClass($trait))->getConstructor()) { $bytes .= 'use ' . $trait . ' { __construct as __trait; }'; $constructor = self::defineForward('__construct', $ctor->getParameters(), 'self::__trait(%s);'); } else { $bytes .= 'use ' . $trait . ';'; } } $declaration['use'] = []; } $bytes = 'static $__func= []; ' . $constructor . $bytes; } } } else { $bytes = substr(trim($def), 1, -1); } if (false !== ($p = strrpos($spec, '.'))) { $header = 'namespace ' . strtr(substr($spec, 0, $p), '.', '\\') . ';'; $name = substr($spec, $p + 1); } else { $header = ''; $name = $spec; \xp::$cn[$name] = $name; } $dyn = self::registerLoader(DynamicClassLoader::instanceFor(__METHOD__)); $dyn->setClassBytes($spec, sprintf('%s%s%s %s%s%s {%s%s}', $header, $typeAnnotations, $declaration['kind'], $name, $declaration['extends'] ? ' extends ' . implode(', ', array_map('self::classLiteral', $declaration['extends'])) : '', $declaration['implements'] ? ' implements ' . implode(', ', array_map('self::classLiteral', $declaration['implements'])) : '', $declaration['use'] ? ' use ' . implode(', ', array_map('self::classLiteral', $declaration['use'])) . ';' : '', $bytes)); $cl = $dyn->loadClass($spec); $functions && $cl->reflect()->setStaticPropertyValue('__func', $functions); return $cl; }
public function cannot_parse_xml() { $class = nameof($this) . $this->name; DynamicClassLoader::instanceFor(self::class)->setClassBytes($class, '', '<?xml version="1.0">'); new ClassSource($class); }
/** * Execute with a given environment settings * * @param array<string, var> env * @return var */ public function executeWith(array $env = []) { with($cl = \lang\DynamicClassLoader::instanceFor(__FUNCTION__), $name = $this->type->name()); $cl->setClassBytes($name, $this->source); $cl->loadClass0($name); }
/** * Creates fixture * * @return lang.IClassLoader */ protected function newFixture() { return DynamicClassLoader::instanceFor('test'); }
/** * Creates an XPClass instance from the specified code using a * DynamicClassLoader. * * @param string bytes * @return lang.XPClass */ private function createClass($bytes) { $dyn = \lang\DynamicClassLoader::instanceFor(__METHOD__); try { $dyn->setClassBytes($this->getProxyName(), $bytes); $class = $dyn->loadClass($this->getProxyName()); } catch (\lang\FormatException $e) { throw new \lang\IllegalArgumentException($e->getMessage()); } return $class; }
/** * Helper method for defineClass() and defineInterface(). * * @param string $spec * @param [:var] $declaration * @param var $def * @return lang.XPClass */ public static function defineType($spec, $declaration, $def) { if ('#' === $spec[0]) { $p = strrpos($spec, ' '); $typeAnnotations = substr($spec, 0, $p) . "\n"; $spec = substr($spec, $p + 1); } else { $typeAnnotations = ''; } if (isset(\xp::$cl[$spec])) { return new XPClass(literal($spec)); } $functions = []; if (is_array($def)) { $iface = 'interface' === $declaration['kind']; $bytes = ''; foreach ($def as $name => $member) { if ('#' === $name[0]) { $p = strrpos($name, ' '); $memberAnnotations = substr($name, 0, $p) . "\n"; $name = substr($name, $p + 1); } else { $memberAnnotations = ''; } if ($member instanceof \Closure) { $bytes .= $memberAnnotations . self::defineForward($name, (new \ReflectionFunction($member))->getParameters(), $iface ? null : 'return self::$__func["' . $name . '"]->call($this%s);', 0); $iface || ($functions[$name] = $member); } else { $bytes .= $memberAnnotations . 'public $' . $name . '= ' . var_export($member, true) . ';'; } } $iface || ($bytes = 'static $__func= []; ' . $bytes); } else { $bytes = substr(trim($def), 1, -1); } if (false !== ($p = strrpos($spec, '.'))) { $header = 'namespace ' . strtr(substr($spec, 0, $p), '.', '\\') . ';'; $name = substr($spec, $p + 1); } else { if (false !== ($p = strrpos($spec, '\\'))) { $header = 'namespace ' . substr($spec, 0, $p) . ';'; $name = substr($spec, $p + 1); $spec = strtr($spec, '\\', '.'); } else { $header = ''; $name = $spec; \xp::$cn[$name] = $name; } } if (isset($declaration['imports'])) { foreach ($declaration['imports'] as $class => $alias) { $header .= 'use ' . substr(self::classLiteral($class), 1) . ($alias ? ' as ' . $alias : '') . ';'; } } $dyn = self::registerLoader(DynamicClassLoader::instanceFor(__METHOD__)); $dyn->setClassBytes($spec, $x = sprintf('%s%s%s %s %s%s%s {%s%s}', $header, $typeAnnotations, $declaration['modifiers'] ?? '', $declaration['kind'], $name, $declaration['extends'] ? ' extends ' . implode(', ', array_map('self::classLiteral', $declaration['extends'])) : '', $declaration['implements'] ? ' implements ' . implode(', ', array_map('self::classLiteral', $declaration['implements'])) : '', $declaration['use'] ? ' use ' . implode(', ', array_map('self::classLiteral', $declaration['use'])) . ';' : '', $bytes)); $cl = $dyn->loadClass($spec); $functions && $cl->reflect()->setStaticPropertyValue('__func', $functions); return $cl; }