/** * Call to undefined method. * * @param string method name * @param array arguments * @return mixed * @throws MemberAccessException */ public static function call($_this, $name, $args) { $class = new ClassReflection($_this); if ($name === '') { throw new MemberAccessException("Call to class '{$class->name}' method without name."); } // event functionality if ($class->hasEventProperty($name)) { if (is_array($list = $_this->{$name}) || $list instanceof Traversable) { foreach ($list as $handler) { fixCallback($handler); if (!is_callable($handler)) { $able = is_callable($handler, TRUE, $textual); throw new InvalidStateException("Event handler '{$textual}' is not " . ($able ? 'callable.' : 'valid PHP callback.')); } call_user_func_array($handler, $args); } } return NULL; } // extension methods if ($cb = $class->getExtensionMethod($name)) { array_unshift($args, $_this); return call_user_func_array($cb, $args); } throw new MemberAccessException("Call to undefined method {$class->name}::{$name}()."); }
/** * Sets a variable in this session namespace. * @param string name * @param mixed value * @return void */ public function __set($name, $value) { $this->data[$name] = $value; if (is_object($value)) { $this->meta[$name]['V'] = ClassReflection::from($value)->getAnnotation('serializationVersion'); } }
/** * Registers adapter for given file extension. * @param string file extension * @param string class name (IConfigAdapter) * @return void */ public static function registerExtension($extension, $class) { if (!class_exists($class)) { throw new InvalidArgumentException("Class '{$class}' was not found."); } if (!ClassReflection::from($class)->implementsInterface('IConfigAdapter')) { throw new InvalidArgumentException("Configuration adapter '{$class}' is not Nette\\Config\\IConfigAdapter implementor."); } self::$extensions[strtolower($extension)] = $class; }
/** * @param string presenter name * @return string class name * @throws InvalidPresenterException */ public function getPresenterClass(&$name) { if (isset($this->cache[$name])) { list($class, $name) = $this->cache[$name]; return $class; } if (!is_string($name) || !preg_match("#^[a-zA-Z-ÿ][a-zA-Z0-9-ÿ:]*\$#", $name)) { throw new InvalidPresenterException("Presenter name must be alphanumeric string, '{$name}' is invalid."); } $class = $this->formatPresenterClass($name); if (!class_exists($class)) { // internal autoloading $file = $this->formatPresenterFile($name); if (is_file($file) && is_readable($file)) { LimitedScope::load($file); } if (!class_exists($class)) { throw new InvalidPresenterException("Cannot load presenter '{$name}', class '{$class}' was not found in '{$file}'."); } } $reflection = new ClassReflection($class); $class = $reflection->getName(); if (!$reflection->implementsInterface('IPresenter')) { throw new InvalidPresenterException("Cannot load presenter '{$name}', class '{$class}' is not Nette\\Application\\IPresenter implementor."); } if ($reflection->isAbstract()) { throw new InvalidPresenterException("Cannot load presenter '{$name}', class '{$class}' is abstract."); } // canonicalize presenter name $realName = $this->unformatPresenterClass($class); if ($name !== $realName) { if ($this->caseSensitive) { throw new InvalidPresenterException("Cannot load presenter '{$name}', case mismatch. Real name is '{$realName}'."); } else { $this->cache[$name] = array($class, $realName); $name = $realName; } } else { $this->cache[$name] = array($class, $realName); } return $class; }
/** * Call to undefined method. * @param string method name * @param array arguments * @return mixed * @throws MemberAccessException */ public static function call($_this, $name, $args) { $class = new ClassReflection($_this); if ($name === '') { throw new MemberAccessException("Call to class '{$class->name}' method without name."); } // event functionality if ($class->hasEventProperty($name)) { if (is_array($list = $_this->{$name}) || $list instanceof Traversable) { foreach ($list as $handler) { callback($handler)->invokeArgs($args); } } return NULL; } // extension methods if ($cb = $class->getExtensionMethod($name)) { array_unshift($args, $_this); return $cb->invokeArgs($args); } throw new MemberAccessException("Call to undefined method {$class->name}::{$name}()."); }
/** * Returns annotations. * @param ReflectionClass|ReflectionMethod|ReflectionProperty * @return array */ public static function getAll(Reflector $r) { if ($r instanceof ReflectionClass) { $type = $r->getName(); $member = ''; } elseif ($r instanceof ReflectionMethod) { $type = $r->getDeclaringClass()->getName(); $member = $r->getName(); } else { $type = $r->getDeclaringClass()->getName(); $member = '$' . $r->getName(); } if (!self::$useReflection) { // auto-expire cache $file = $r instanceof ReflectionClass ? $r->getFileName() : $r->getDeclaringClass()->getFileName(); // will be used later if ($file && isset(self::$timestamps[$file]) && self::$timestamps[$file] !== filemtime($file)) { unset(self::$cache[$type]); } unset(self::$timestamps[$file]); } if (isset(self::$cache[$type][$member])) { // is value cached? return self::$cache[$type][$member]; } if (self::$useReflection === NULL) { // detects whether is reflection available self::$useReflection = (bool) ClassReflection::from(__CLASS__)->getDocComment(); } if (self::$useReflection) { return self::$cache[$type][$member] = self::parseComment($r->getDocComment()); } else { if (self::$cache === NULL) { self::$cache = (array) self::getCache()->offsetGet('list'); self::$timestamps = isset(self::$cache['*']) ? self::$cache['*'] : array(); } if (!isset(self::$cache[$type]) && $file) { self::$cache['*'][$file] = filemtime($file); self::parseScript($file); self::getCache()->save('list', self::$cache); } if (isset(self::$cache[$type][$member])) { return self::$cache[$type][$member]; } else { return self::$cache[$type][$member] = array(); } } }
/** * __call() implementation. * @param object * @param string * @param array * @return mixed * @throws MemberAccessException */ public static function call($_this, $name, $args) { $class = get_class($_this); $isProp = self::hasProperty($class, $name); if ($name === '') { throw new MemberAccessException("Call to class '{$class}' method without name."); } elseif ($isProp === 'event') { // calling event handlers if (is_array($_this->{$name}) || $_this->{$name} instanceof Traversable) { foreach ($_this->{$name} as $handler) { Callback::create($handler)->invokeArgs($args); } } elseif ($_this->{$name} !== NULL) { throw new UnexpectedValueException("Property {$class}::\${$name} must be array or NULL, " . gettype($_this->{$name}) . " given."); } } elseif ($cb = ClassReflection::from($_this)->getExtensionMethod($name)) { // extension methods array_unshift($args, $_this); return $cb->invokeArgs($args); } else { throw new MemberAccessException("Call to undefined method {$class}::{$name}()."); } }
/** * @return ClassReflection */ public function getDeclaringClass() { return ($ref = parent::getDeclaringClass()) ? ClassReflection::import($ref) : NULL; }
/** * Adding method to class. * @param string method name * @param mixed callback or closure * @return mixed */ public static function extensionMethod($name, $callback = NULL) { if (strpos($name, '::') === FALSE) { $class = get_called_class(); } else { list($class, $name) = explode('::', $name); } $class = new ClassReflection($class); if ($callback === NULL) { return $class->getExtensionMethod($name); } else { $class->setExtensionMethod($name, $callback); } }
/** * @return ClassReflection */ public function getDeclaringClass() { return ClassReflection::import(parent::getDeclaringClass()); }
/** * Checks object @serializationVersion label. * @param string * @param mixed * @return bool */ private static function checkSerializationVersion($class, $value) { return ClassReflection::from($class)->getAnnotation('serializationVersion') === $value; }
/** * Starts and initializes session data. * @throws InvalidStateException * @return void */ public function start() { if (self::$started) { return; } $this->configure($this->options); Debugger::tryError(); session_start(); if (Debugger::catchError($e) && !session_id()) { @session_write_close(); // this is needed throw new InvalidStateException('session_start(): ' . $e->getMessage(), 0, $e); } self::$started = TRUE; /* structure: __NF: Counter, BrowserKey, Data, Meta, Time DATA: section->variable = data META: section->variable = Timestamp, Browser, Version */ unset($_SESSION['__NT'], $_SESSION['__NS'], $_SESSION['__NM']); // old unused structures // initialize structures $nf =& $_SESSION['__NF']; if (empty($nf)) { // new session $nf = array('C' => 0); } else { $nf['C']++; } // session regenerate every 30 minutes $nfTime =& $nf['Time']; $time = time(); if ($time - $nfTime > self::REGENERATE_INTERVAL) { $this->regenerated = $this->regenerated || isset($nfTime); $nfTime = $time; } // browser closing detection $browserKey = $this->request->getCookie('nette-browser'); if (!$browserKey) { $browserKey = Strings::random(); } $browserClosed = !isset($nf['B']) || $nf['B'] !== $browserKey; $nf['B'] = $browserKey; // resend cookie $this->sendCookie(); // process meta metadata if (isset($nf['META'])) { $now = time(); // expire section variables foreach ($nf['META'] as $section => $metadata) { if (is_array($metadata)) { foreach ($metadata as $variable => $value) { if (!empty($value['B']) && $browserClosed || !empty($value['T']) && $now > $value['T'] || isset($nf['DATA'][$section][$variable]) && is_object($nf['DATA'][$section][$variable]) && (isset($value['V']) ? $value['V'] : NULL) != ClassReflection::from($nf['DATA'][$section][$variable])->getAnnotation('serializationVersion')) { if ($variable === '') { // expire whole section unset($nf['META'][$section], $nf['DATA'][$section]); continue 2; } unset($nf['META'][$section][$variable], $nf['DATA'][$section][$variable]); } } } } } if ($this->regenerated) { $this->regenerated = FALSE; $this->regenerateId(); } register_shutdown_function(array($this, 'clean')); }
/** * Tests reflector type. */ public function teGetReflector() { $reflectedClass = new ClassReflection('TRex\\Reflection\\resources\\Foo'); $this->assertInstanceOf('\\ReflectionClass', $reflectedClass->getReflector()); }
/** * Starts and initializes session data. * @throws InvalidStateException * @return void */ public function start() { if (self::$started) { throw new InvalidStateException('Session has already been started.'); } elseif (self::$started === NULL && defined('SID')) { throw new InvalidStateException('A session had already been started by session.auto-start or session_start().'); } // start session try { $this->configure($this->options); } catch (NotSupportedException $e) { // ignore? } Debug::tryError(); session_start(); if (Debug::catchError($msg)) { @session_write_close(); // this is needed throw new InvalidStateException($msg); } self::$started = TRUE; if ($this->regenerationNeeded) { session_regenerate_id(TRUE); $this->regenerationNeeded = FALSE; } /* structure: __NF: Counter, BrowserKey, Data, Meta DATA: namespace->variable = data META: namespace->variable = Timestamp, Browser, Version */ unset($_SESSION['__NT'], $_SESSION['__NS'], $_SESSION['__NM']); // old unused structures // initialize structures $nf =& $_SESSION['__NF']; if (empty($nf)) { // new session $nf = array('C' => 0); } else { $nf['C']++; } // browser closing detection $browserKey = $this->getHttpRequest()->getCookie('nette-browser'); if (!$browserKey) { $browserKey = (string) lcg_value(); } $browserClosed = !isset($nf['B']) || $nf['B'] !== $browserKey; $nf['B'] = $browserKey; // resend cookie $this->sendCookie(); // process meta metadata if (isset($nf['META'])) { $now = time(); // expire namespace variables foreach ($nf['META'] as $namespace => $metadata) { if (is_array($metadata)) { foreach ($metadata as $variable => $value) { if (!empty($value['B']) && $browserClosed || !empty($value['T']) && $now > $value['T'] || $variable !== '' && is_object($nf['DATA'][$namespace][$variable]) && (isset($value['V']) ? $value['V'] : NULL) !== ClassReflection::from($nf['DATA'][$namespace][$variable])->getAnnotation('serializationVersion')) { if ($variable === '') { // expire whole namespace unset($nf['META'][$namespace], $nf['DATA'][$namespace]); continue 2; } unset($nf['META'][$namespace][$variable], $nf['DATA'][$namespace][$variable]); } } } } } register_shutdown_function(array($this, 'clean')); }
public function __construct($object) { $this->setObject($object); parent::__construct(get_class($object)); }
/** * Starts and initializes session data. * @throws InvalidStateException * @return void */ public function start() { if (self::$started) { throw new InvalidStateException('Session has already been started.'); } elseif (self::$started === NULL && defined('SID')) { throw new InvalidStateException('A session had already been started by session.auto-start or session_start().'); } // additional protection against Session Hijacking & Fixation if ($this->verificationKeyGenerator) { fixCallback($this->verificationKeyGenerator); if (!is_callable($this->verificationKeyGenerator)) { $able = is_callable($this->verificationKeyGenerator, TRUE, $textual); throw new InvalidStateException("Verification key generator '{$textual}' is not " . ($able ? 'callable.' : 'valid PHP callback.')); } } // start session try { $this->configure($this->options); } catch (NotSupportedException $e) { // ignore? } Tools::tryError(); session_start(); if (Tools::catchError($msg)) { @session_write_close(); // this is needed throw new InvalidStateException($msg); } self::$started = TRUE; if ($this->regenerationNeeded) { session_regenerate_id(TRUE); $this->regenerationNeeded = FALSE; } /* structure: __NF: VerificationKey, Counter, BrowserKey, Data, Meta DATA: namespace->variable = data META: namespace->variable = Timestamp, Browser, Version */ // initialize structures $verKey = $this->verificationKeyGenerator ? (string) call_user_func($this->verificationKeyGenerator) : NULL; if (!isset($_SESSION['__NF']['V'])) { // new session $_SESSION['__NF'] = array(); $_SESSION['__NF']['C'] = 0; $_SESSION['__NF']['V'] = $verKey; } else { $saved =& $_SESSION['__NF']['V']; if (!$this->verificationKeyGenerator || $verKey === $saved) { // ignored or verified $_SESSION['__NF']['C']++; } else { // session attack? session_regenerate_id(TRUE); $_SESSION = array(); $_SESSION['__NF']['C'] = 0; $_SESSION['__NF']['V'] = $verKey; } } $nf =& $_SESSION['__NF']; unset($_SESSION['__NT'], $_SESSION['__NS'], $_SESSION['__NM']); // old structures // browser closing detection $browserKey = $this->getHttpRequest()->getCookie('nette-browser'); if (!$browserKey) { $browserKey = (string) lcg_value(); } $browserClosed = !isset($nf['B']) || $nf['B'] !== $browserKey; $nf['B'] = $browserKey; // resend cookie $this->sendCookie(); // process meta metadata if (isset($nf['META'])) { $now = time(); // expire namespace variables foreach ($nf['META'] as $namespace => $metadata) { if (is_array($metadata)) { foreach ($metadata as $variable => $value) { if (!empty($value['B']) && $browserClosed || !empty($value['T']) && $now > $value['T'] || $variable !== '' && is_object($nf['DATA'][$namespace][$variable]) && (isset($value['V']) ? $value['V'] : NULL) !== ClassReflection::from($nf['DATA'][$namespace][$variable])->getAnnotation('serializationVersion')) { if ($variable === '') { // expire whole namespace unset($nf['META'][$namespace], $nf['DATA'][$namespace]); continue 2; } unset($nf['META'][$namespace][$variable], $nf['DATA'][$namespace][$variable]); } } } } } register_shutdown_function(array($this, 'clean')); }
public function getAliases() { if (false === $this->loaded) { $this->load(); } return parent::getAliases(); }
/** * Returns annotations. * @param ReflectionClass|ReflectionMethod|ReflectionProperty * @return array */ public static function getAll(Reflector $r) { if ($r instanceof ReflectionClass) { $type = $r->getName(); $member = ''; } elseif ($r instanceof ReflectionMethod) { $type = $r->getDeclaringClass()->getName(); $member = $r->getName(); } else { $type = $r->getDeclaringClass()->getName(); $member = '$' . $r->getName(); } if (!self::$useReflection) { // auto-expire cache $file = $r instanceof ReflectionClass ? $r->getFileName() : $r->getDeclaringClass()->getFileName(); // will be used later if ($file && isset(self::$timestamps[$file]) && self::$timestamps[$file] !== filemtime($file)) { unset(self::$cache[$type]); } unset(self::$timestamps[$file]); } if (isset(self::$cache[$type][$member])) { // is value cached? return self::$cache[$type][$member]; } if (self::$useReflection === NULL) { // detects whether is reflection available self::$useReflection = (bool) ClassReflection::from(__CLASS__)->getDocComment(); } if (self::$useReflection) { $annotations = self::parseComment($r->getDocComment()); } else { if (!self::$cacheStorage) { // trigger_error('Set a cache storage for annotations parser via AnnotationParser::setCacheStorage().', E_USER_WARNING); self::$cacheStorage = new DevNullStorage(); } $outerCache = new Cache(self::$cacheStorage, 'Nette.Reflection.Annotations'); if (self::$cache === NULL) { self::$cache = (array) $outerCache->offsetGet('list'); self::$timestamps = isset(self::$cache['*']) ? self::$cache['*'] : array(); } if (!isset(self::$cache[$type]) && $file) { self::$cache['*'][$file] = filemtime($file); self::parseScript($file); $outerCache->save('list', self::$cache); } if (isset(self::$cache[$type][$member])) { $annotations = self::$cache[$type][$member]; } else { $annotations = array(); } } if ($r instanceof ReflectionMethod && !$r->isPrivate() && (!$r->isConstructor() || !empty($annotations['inheritdoc'][0]))) { try { $inherited = self::getAll(new ReflectionMethod(get_parent_class($type), $member)); } catch (ReflectionException $e) { try { $inherited = self::getAll($r->getPrototype()); } catch (ReflectionException $e) { $inherited = array(); } } $annotations += array_intersect_key($inherited, array_flip(self::$inherited)); } return self::$cache[$type][$member] = $annotations; }
/** * Returns array of classes persistent parameters. They have public visibility and are non-static. * This default implementation detects persistent parameters by annotation @persistent. * @return array */ public static function getPersistentParams() { $rc = new ClassReflection(func_get_arg(0)); $params = array(); foreach ($rc->getProperties(ReflectionProperty::IS_PUBLIC) as $rp) { if (!$rp->isStatic() && $rp->hasAnnotation('persistent')) { $params[] = $rp->getName(); } } return $params; }
private function getContainerProperty($name) { $prop = ClassReflection::from('DIContainer')->getProperty($name); $prop->setAccessible(TRUE); return $prop->getValue($this->container); }
/** * Returns array of persistent components. * This default implementation detects components by class-level annotation @persistent(cmp1, cmp2). * @return array */ public static function getPersistentComponents() { return (array) ClassReflection::from(func_get_arg(0))->getAnnotation('persistent'); }
/** * Creates new instance using autowiring. * @param string class * @param array arguments * @return object * @throws InvalidArgumentException */ public function createInstance($class, array $args = array()) { $rc = ClassReflection::from($class); if (!$rc->isInstantiable()) { throw new ServiceCreationException("Class {$class} is not instantiable."); } elseif ($constructor = $rc->getConstructor()) { return $rc->newInstanceArgs(DIHelpers::autowireArguments($constructor, $args, $this)); } elseif ($args) { throw new ServiceCreationException("Unable to pass arguments, class {$class} has no constructor."); } return new $class(); }
/** * Formats PHP code for class instantiating, function calling or property setting in PHP. * @return string * @internal */ public function formatStatement(DIStatement $statement, $self = NULL) { $entity = $this->normalizeEntity($statement->entity); $arguments = $statement->arguments; if (is_string($entity) && Strings::contains($entity, '?')) { // PHP literal return $this->formatPhp($entity, $arguments, $self); } elseif ($service = $this->getServiceName($entity)) { // factory calling or service retrieving if ($this->definitions[$service]->shared) { if ($arguments) { throw new ServiceCreationException("Unable to call service '{$entity}'."); } return $this->formatPhp('$this->getService(?)', array($service)); } $params = array(); foreach ($this->definitions[$service]->parameters as $k => $v) { $params[] = preg_replace('#\\w+$#', '\\$$0', is_int($k) ? $v : $k) . (is_int($k) ? '' : ' = ' . PhpHelpers::dump($v)); } $rm = new FunctionReflection(create_function(implode(', ', $params), '')); $arguments = DIHelpers::autowireArguments($rm, $arguments, $this); return $this->formatPhp('$this->?(?*)', array(DIContainer::getMethodName($service, FALSE), $arguments), $self); } elseif ($entity === 'not') { // operator return $this->formatPhp('!?', array($arguments[0])); } elseif (is_string($entity)) { // class name if ($constructor = ClassReflection::from($entity)->getConstructor()) { $this->addDependency($constructor->getFileName()); $arguments = DIHelpers::autowireArguments($constructor, $arguments, $this); } elseif ($arguments) { throw new ServiceCreationException("Unable to pass arguments, class {$entity} has no constructor."); } return $this->formatPhp("new {$entity}" . ($arguments ? '(?*)' : ''), array($arguments), $self); } elseif (!Validators::isList($entity) || count($entity) !== 2) { throw new InvalidStateException("Expected class, method or property, " . PhpHelpers::dump($entity) . " given."); } elseif ($entity[0] === '') { // globalFunc return $this->formatPhp("{$entity['1']}(?*)", array($arguments), $self); } elseif (Strings::contains($entity[1], '$')) { // property setter Validators::assert($arguments, 'list:1', "setup arguments for '" . Callback::create($entity) . "'"); if ($this->getServiceName($entity[0], $self)) { return $this->formatPhp('?->? = ?', array($entity[0], substr($entity[1], 1), $arguments[0]), $self); } else { return $this->formatPhp($entity[0] . '::$? = ?', array(substr($entity[1], 1), $arguments[0]), $self); } } elseif ($service = $this->getServiceName($entity[0], $self)) { // service method if ($this->definitions[$service]->class) { $arguments = $this->autowireArguments($this->definitions[$service]->class, $entity[1], $arguments); } return $this->formatPhp('?->?(?*)', array($entity[0], $entity[1], $arguments), $self); } else { // static method $arguments = $this->autowireArguments($entity[0], $entity[1], $arguments); return $this->formatPhp("{$entity['0']}::{$entity['1']}(?*)", array($arguments), $self); } }
public function generateCode($className, $parentName) { foreach ($this->extensions as $extension) { $extension->beforeCompile(); $this->container->addDependency(ClassReflection::from($extension)->getFileName()); } $classes[] = $class = $this->container->generateClass($parentName); $class->setName($className)->addMethod('initialize'); foreach ($this->extensions as $extension) { $extension->afterCompile($class); } $defs = $this->container->getDefinitions(); ksort($defs); $list = array_keys($defs); foreach (array_reverse($defs, TRUE) as $name => $def) { if ($def->class === 'DINestedAccessor' && ($found = preg_grep('#^' . $name . '\\.#i', $list))) { $list = array_diff($list, $found); $def->class = $className . '_' . preg_replace('#\\W+#', '_', $name); $class->documents = preg_replace("#\\S+(?= \\\${$name}\$)#", $def->class, $class->documents); $classes[] = $accessor = new PhpClassType($def->class); foreach ($found as $item) { if ($defs[$item]->internal) { continue; } $short = substr($item, strlen($name) + 1); $accessor->addDocument($defs[$item]->shared ? "@property {$defs[$item]->class} \${$short}" : "@method {$defs[$item]->class} create" . ucfirst("{$short}()")); } } } return implode("\n\n\n", $classes); }
public function testGetAnnotations() { $reflectedClass = new ClassReflection('TRex\\Reflection\\resources\\Foo'); $this->assertInstanceOf('TRex\\Annotation\\Annotations', $reflectedClass->getAnnotations()); $this->assertSame('TRex\\Reflection\\resources', $reflectedClass->getAnnotations()->get('package')->first()); }