/** * Recursively traverses and wraps all Closure objects within the value. * * NOTE: THIS MAY NOT WORK IN ALL USE CASES, SO USE AT YOUR OWN RISK. * * @param mixed $data Any variable that contains closures. * @param SerializerInterface $serializer The serializer to use. */ public static function wrapClosures(&$data, SerializerInterface $serializer) { if ($data instanceof \Closure) { // Handle and wrap closure objects. $reflection = new \ReflectionFunction($data); if ($binding = $reflection->getClosureThis()) { self::wrapClosures($binding, $serializer); $scope = $reflection->getClosureScopeClass(); $scope = $scope ? $scope->getName() : 'static'; $data = $data->bindTo($binding, $scope); } $data = new SerializableClosure($data, $serializer); } elseif (is_array($data) || $data instanceof \stdClass || $data instanceof \Traversable) { // Handle members of traversable values. foreach ($data as &$value) { self::wrapClosures($value, $serializer); } } elseif (is_object($data) && !$data instanceof \Serializable) { // Handle objects that are not already explicitly serializable. $reflection = new \ReflectionObject($data); if (!$reflection->hasMethod('__sleep')) { foreach ($reflection->getProperties() as $property) { if ($property->isPrivate() || $property->isProtected()) { $property->setAccessible(true); } $value = $property->getValue($data); self::wrapClosures($value, $serializer); $property->setValue($data, $value); } } } }
/** * Checks if callable is bindable. * * @param \Closure $callable * @return bool */ function isBindable(Closure $callable) { $bindable = false; $reflectionFunction = new \ReflectionFunction($callable); if ($reflectionFunction->getClosureScopeClass() === null || $reflectionFunction->getClosureThis() !== null) { $bindable = true; } return $bindable; }
/** * Hash anything, return the unique identity. * * @param $object * @return string */ protected function hash($object) { array_walk_recursive($object, function (&$item) { if ($item instanceof \Closure) { $reflection = new \ReflectionFunction($item); $item = serialize($reflection->getClosureScopeClass()) . $reflection->getNumberOfParameters() . $reflection->getNamespaceName() . $reflection->getStartLine() . $reflection->getEndLine(); } }); return md5(serialize($object)); }
/** * Hash anything (except PDO connection stuff, for now). * * @param mixed $object * @return string */ public static function hash($object) { $object = is_array($object) ? $object : [$object]; array_walk_recursive($object, function ($item) { if ($item instanceof \Closure) { $reflection = new \ReflectionFunction($item); // Unique and fast. $item = serialize($reflection->getClosureScopeClass()) . $reflection->getNumberOfParameters() . $reflection->getNamespaceName() . $reflection->getStartLine() . $reflection->getEndLine(); } }); return md5(serialize($object)); }
/** * Creates a ClosureLocation and seeds it with all the data that can be gleaned from the closure's reflection * * @param \ReflectionFunction $reflection The reflection of the closure that this ClosureLocation should represent * * @return ClosureLocation */ public static function fromReflection(\ReflectionFunction $reflection) { $location = new self(); $location->directory = dirname($reflection->getFileName()); $location->file = $reflection->getFileName(); $location->function = $reflection->getName(); $location->line = $reflection->getStartLine(); // @codeCoverageIgnoreStart if (version_compare(PHP_VERSION, '5.4', '>=')) { $closureScopeClass = $reflection->getClosureScopeClass(); $location->closureScopeClass = $closureScopeClass ? $closureScopeClass->getName() : null; } // @codeCoverageIgnoreEnd return $location; }
public function afterTraverse(array $nodes) { if ($this->location['class']) { $this->location['class'] = $this->location['namespace'] . '\\' . $this->location['class']; $this->location['method'] = "{$this->location['class']}::{$this->location['function']}"; } elseif ($this->location['trait']) { $this->location['trait'] = $this->location['namespace'] . '\\' . $this->location['trait']; $this->location['method'] = "{$this->location['trait']}::{$this->location['function']}"; } if (!$this->location['class']) { /** @var \ReflectionClass $closureScopeClass */ $closureScopeClass = $this->reflection->getClosureScopeClass(); $this->location['class'] = $closureScopeClass ? $closureScopeClass->getName() : null; } }
public static function unwrap(\Closure $closure) { $reflectionFunction = new \ReflectionFunction($closure); if (substr($reflectionFunction->getName(), -1) === '}') { $vars = $reflectionFunction->getStaticVariables(); return isset($vars['_callable_']) ? $vars['_callable_'] : $closure; } else { if ($obj = $reflectionFunction->getClosureThis()) { return [$obj, $reflectionFunction->getName()]; } else { if ($class = $reflectionFunction->getClosureScopeClass()) { return [$class->getName(), $reflectionFunction->getName()]; } } } return $reflectionFunction->getName(); }
public function afterTraverse(array $nodes) { if ($this->location['class']) { $this->location['class'] = $this->location['namespace'] . '\\' . $this->location['class']; $this->location['method'] = "{$this->location['class']}::{$this->location['function']}"; } elseif ($this->location['trait']) { $this->location['trait'] = $this->location['namespace'] . '\\' . $this->location['trait']; $this->location['method'] = "{$this->location['trait']}::{$this->location['function']}"; // If the closure was declared in a trait, then we will do a best // effort guess on the name of the class that used the trait. It's // actually impossible at this point to know for sure what it is. if ($closureScope = $this->reflection->getClosureScopeClass()) { $this->location['class'] = $closureScope ? $closureScope->getName() : null; } elseif ($closureThis = $this->reflection->getClosureThis()) { $this->location['class'] = get_class($closureThis); } } }
/** * @param callable $listener * * @return string */ private function getControllerName($listener) : string { if (is_array($listener)) { if (is_string($listener[0])) { return $listener[0] . '::' . $listener[1]; } else { return get_class($listener[0]) . '::' . $listener[1]; } } elseif (is_string($listener)) { return $listener; } else { $reflection = new \ReflectionFunction($listener); return $reflection->getClosureScopeClass()->getName() . '::' . 'closure[' . $reflection->getStartLine() . ':' . $reflection->getEndLine() . ']'; } }
<?php $c = function () { var_dump($this); }; $d = $c->bindTo(new stdClass()); $d(); $rm = new ReflectionFunction($d); var_dump($rm->getClosureScopeClass()->name); //dummy sope is Closure //should have the same effect $d = $c->bindTo(new stdClass(), NULL); $d(); $rm = new ReflectionFunction($d); var_dump($rm->getClosureScopeClass()->name); //dummy sope is Closure echo "Done.\n";
<?php $closure = function ($param) { return "this is a closure"; }; $rf = new ReflectionFunction($closure); var_dump($rf->getClosureScopeClass()); class A { public static function getClosure() { return function ($param) { return "this is a closure"; }; } } $closure = A::getClosure(); $rf = new ReflectionFunction($closure); var_dump($rf->getClosureScopeClass()); echo "Done!\n";