In order to improve AoT compiler, on my project I've done some changes.
The problem is that with AoT, dependency factories are not created. To accomplish my goal I've made a simple DependencyScanner that try to fetch every dependency classes:
<?php
declare(strict_types=1);
namespace AppAoT\Scanner;
use Zend\Code\Reflection\ClassReflection;
class DependencyScanner
{
/** @var string[] */
private $classNamesToScan;
/** @var string[] */
private $classNames = [];
/** @var bool */
private $isScanned = false;
/**
* DependencyScanner constructor.
*
* @param string[] $classNamesToScan
*/
public function __construct(array $classNamesToScan = [])
{
$this->classNamesToScan = $classNamesToScan;
}
protected function scan(): void
{
if ($this->isScanned) {
return;
}
foreach ($this->classNamesToScan as $className)
{
$this->scanClass($className);
}
$this->isScanned = true;
}
protected function scanClass(string $name): void
{
if (! \class_exists($name)) {
return;
}
if (\array_key_exists($name, $this->classNames)) {
return;
}
$this->classNames[$name] = true;
$classReflection = new ClassReflection($name);
$constructor = $classReflection->getConstructor();
if (null === $constructor) {
return;
}
$parameters = $constructor->getParameters();
foreach ($parameters as $parameter) {
$class = $parameter->getClass();
if (null === $class) {
continue;
}
$this->scanClass($class->getName());
}
}
/**
* @return string[]
*/
public function getClassNames(): array
{
$this->scan();
return \array_keys($this->classNames);
}
}
And changed my di-generate-aot.sh to use it, getting every psr-4 namespace directory (does not support dir arrays yet), and using the previous class to fetch every dependency class.
<?php
namespace AppAoT;
use AppAoT\Scanner\DependencyScanner;
use Psr\Container\ContainerInterface;
use Zend\Code\Scanner\DirectoryScanner;
use Zend\Di\CodeGenerator\InjectorGenerator;
use Zend\Di\ConfigInterface;
use Zend\Di\Definition\RuntimeDefinition;
use Zend\Di\Resolver\DependencyResolver;
require __DIR__ . '/../vendor/autoload.php';
$composerFile = __DIR__ . '/../composer.json';
if (! \is_readable($composerFile)) {
throw new \RuntimeException('Unable to find composer.json');
}
$composer = \json_decode(\file_get_contents($composerFile), true);
$directories = \array_values($composer['autoload']['psr-4'] ?? []);
/** @var ContainerInterface $container */
$container = require __DIR__ . '/../config/container.php';
$config = $container->get(ConfigInterface::class);
$resolver = new DependencyResolver(new RuntimeDefinition(), $config);
$resolver->setContainer($container);
$scanner = new DirectoryScanner($directories);
$dependencyScanner = new DependencyScanner($scanner->getClassNames());
$classNames = $dependencyScanner->getClassNames();
$generator = new InjectorGenerator($config, $resolver, __NAMESPACE__ . '\Generated');
$generator->setOutputDirectory(__DIR__ . '/../src/AppAoT/gen');
$generator->generate($classNames);
It's just an example, but I think we can include something like that in zend-code and/or here, and improve the documentation in order to provide a better AoT compiler compared to others compiled containers.
P.S. It does not resolve aliases yet.
Originally posted by @thomasvargiu at zendframework/zend-di#42
In order to improve AoT compiler, on my project I've done some changes.
The problem is that with AoT, dependency factories are not created. To accomplish my goal I've made a simple DependencyScanner that try to fetch every dependency classes:
And changed my
di-generate-aot.shto use it, getting everypsr-4namespace directory (does not support dir arrays yet), and using the previous class to fetch every dependency class.It's just an example, but I think we can include something like that in
zend-codeand/or here, and improve the documentation in order to provide a better AoT compiler compared to others compiled containers.P.S. It does not resolve aliases yet.
Originally posted by @thomasvargiu at zendframework/zend-di#42