Last active
September 9, 2015 04:26
-
-
Save tyler-sommer/9285127 to your computer and use it in GitHub Desktop.
Adding closures to compiled symfony 2 containers
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// Generated container classs | |
class DevProjectContainer extends Container | |
{ | |
/** | |
* Gets the 'twig.loader' service. | |
* | |
* This service is shared. | |
* This method always returns the same instance of the service. | |
* | |
* @return Twig_Loader_Filesystem A Twig_Loader_Filesystem instance. | |
*/ | |
protected function getTwig_LoaderService() | |
{ | |
$this->services['twig.loader'] = $instance = new \Twig_Loader_Filesystem(array()); | |
$container = $this; | |
$closure = function(\Twig_Loader_Filesystem $loader) use ($container) { | |
$loader->setPaths($container->getParameter('twig.template_dir')); | |
}; | |
$closure($instance); | |
return $instance; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Serializable Closure | |
* | |
* Allows the serialization of a closure, specifically a Closure, for storage | |
*/ | |
class SerializableCallable implements \Serializable | |
{ | |
/** | |
* @var callable | |
*/ | |
protected $closure; | |
/** | |
* @param callable $closure Either a Closure object or a valid callable | |
*/ | |
public function __construct($closure) | |
{ | |
if (is_array($closure) && is_object($closure[0])) { | |
throw new \RuntimeException('Closures on object instances is not currently supported.'); | |
} | |
else if (!is_callable($closure)) { | |
throw new \RuntimeException('Closure is not callable.'); | |
} | |
$this->closure = $closure; | |
} | |
/** | |
* Invokes the stored closure | |
*/ | |
public function __invoke() | |
{ | |
$args = func_get_args(); | |
return call_user_func_array($this->closure, $args); | |
} | |
/** | |
* Gets $closure | |
* | |
* @return callable | |
*/ | |
public function getClosure() | |
{ | |
return $this->closure; | |
} | |
public function __toString() | |
{ | |
if (!($this->closure instanceof \Closure)) { | |
// Is a normal closure, just serialize it | |
return serialize(array('closure' => $this->closure)); | |
} | |
$reflected = new \ReflectionFunction($this->closure); | |
$code = $this->_getCode($reflected); | |
$context = $reflected->getStaticVariables(); | |
$code = '$container = $this;' . "\n" . '$closure = ' . $code . ';' . "\n" . '$closure'; | |
return $code; | |
} | |
/** | |
* @see Serializable::serialize() | |
*/ | |
public function serialize() | |
{ | |
if (!($this->closure instanceof \Closure)) { | |
// Is a normal closure, just serialize it | |
return serialize(array('closure' => $this->closure)); | |
} | |
$reflected = new \ReflectionFunction($this->closure); | |
$code = $this->_getCode($reflected); | |
$context = $reflected->getStaticVariables(); | |
return serialize(array('code' => $code, 'context' => $context)); | |
} | |
/** | |
* @see Serializable::unserialize() | |
*/ | |
public function unserialize($data) | |
{ | |
$data = unserialize($data); | |
if (!$data) { | |
throw new \RuntimeException('Could not unserialize Closure. Unserialization failed.'); | |
} | |
if (empty($data['closure'])) { | |
$code = $data['code']; | |
$context = $data['context']; | |
extract($context); | |
@eval("\$_closure = $code;"); | |
if (!isset($_closure) || !is_callable($_closure)) throw new \RuntimeException('Could not unserialize Closure. Invalid Closure specified.'); | |
$this->closure = $_closure; | |
} | |
else { | |
$this->closure = $data['closure']; | |
} | |
} | |
/** | |
* Iterates on source files to return actual implementation of code | |
* | |
* @param \ReflectionFunction $reflected | |
*/ | |
protected function _getCode(\ReflectionFunction $reflected) | |
{ | |
$file = new \SplFileObject($reflected->getFileName()); | |
$file->seek($reflected->getStartLine() - 1); | |
$code = ''; | |
while ($file->key() < $reflected->getEndLine()) { | |
$code .= $file->current(); | |
$file->next(); | |
} | |
$begin = strpos($code, 'function'); | |
$end = strrpos($code, '}'); | |
$code = substr($code, $begin, $end - $begin + 1); | |
return $code; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// Inside AppKernel.php somewhere | |
$getTemplateDir = new SerializableCallable(function(\Twig_Loader_Filesystem $loader) use ($container) { | |
$loader->setPaths($container->getParameter('twig.template_dir')); | |
}); | |
$container->setParameter('twig.template_dir', $this->getRootDir() . '/views'); | |
$container->register('twig.loader', 'Twig_Loader_Filesystem') | |
->addArgument(array()) | |
->setConfigurator($getTemplateDir); | |
$container->compile(); | |
$this->dumpContainer($cache, $container, $class, 'Container'); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment