Adds automatic code generation feature to PHP-DI.
- No need to write
Factoriesfor stateful objects anymore.
(*)Note this package is a feature extension for PHP-DI and only works if the system makes use of the PHP-DI's container.
- PHP >= 7.2
- php-di/php-di >= 6.3.5
composer require wubinworks/php-di-code-generatorcodeDirectory
This directory will contain the generated PHP files and should reside inside the project root directory.
The recommended path is '<Project Root>/generated/code'.
logger
This parameter(PSR-3: Logger Interface) is optional and must be null|\Psr\Log\LoggerInterface.
...
// Definition for setting up the code generator's autoloader
/** @var \DI\ContainerBuilder $containerBuilder */
$containerBuilder->addDefinitions([
'Wubinworks\PHPDICodeGenerator\Code\Generation\Generator\*Generator' => \DI\autowire()
->constructorParameter('codeDirectory', '<Project Root>/generated/code'),
\Wubinworks\PHPDICodeGenerator\Code\Generation\Autoloader::class => \DI\autowire()
->constructorParameter('generators', [
\DI\get(\Wubinworks\PHPDICodeGenerator\Code\Generation\Generator\FactoryGenerator::class)
])
->constructorParameter('logger', static function () {
$logger = new \Monolog\Logger('code-generator');
$logger->pushHandler(new \Monolog\Handler\StreamHandler('<Project Root>/var/log/code-generator.log'));
return $logger;
})
]);
...
/** @var \DI\Container|\Psr\Container\ContainerInterface $container */
$container = $containerBuilder->build();$container->get(\Wubinworks\PHPDICodeGenerator\Code\Generation\Autoloader::class)
->register();Note this step is optional, but is strongly recommended for performance improvement.
...
{
"autoload": {
...
"psr-4": {
"": [
...
"generated/code/",
...
]
}
...
}
}
...When the container is looking for a class whose name ends with Factory and that class does not exist, the code generator's autoloader is triggered. Then the missing Factory's PHP file will be generated and included.
Suppose you already have \Vendor\Namespace\StatefulObject class and it can be autoloaded (by composer's autoloader). Usually, you need to write a Factory class in order to create different instances of that stateful object.
With this code generator, you do not need to write those Factory classes anymore.
What you need to do is just to append the Factory suffix to \Vendor\Namespace\StatefulObject.
use Vendor\Namespace\StatefulObject;
use Vendor\Namespace\StatefulObjectFactory; // Appended the Factory suffix
// Confirm \Vendor\Namespace\StatefulObjectFactory class does NOT exist without autoloading
var_dump(class_exists(StatefulObjectFactory::class), false);
// falseclass Example
{
/**
* @var StatefulObjectFactory
*/
private $statefulObjectFactory;
/**
* Constructor
*
* Use PHP-DI's dependency injection
*
* @param StatefulObjectFactory $statefulObjectFactory
* ...
*/
public function __construct(
StatefulObjectFactory $statefulObjectFactory,
...
) {
$this->statefulObjectFactory = $statefulObjectFactory;
...
// Confirm now \Vendor\Namespace\StatefulObjectFactory exists without autoloading
var_dump(class_exists(StatefulObjectFactory::class), false);
// true
// Because `\Vendor\Namespace\StatefulObjectFactory`'s PHP file has been generated and included
}
...
}Note the following ways also work but are HIGHLY DEPRECATED. You should use the PHP-DI's constructor/property injection instead.
$factory = new StatefulObjectFactory();/** @var \Psr\Container\ContainerInterface $container */
$factory = $container->get(StatefulObjectFactory::class);Then you can confirm file <Project Root>/generated/code/Vendor/Namespace/StatefulObjectFactory.php has been generated.
Note class_exists(StatefulObjectFactory::class, /** The second parameter is true */ true) can also trigger the code generation.
The generated Factory always has a create method and this method takes an array of constructor parameters of the object it can create.
$statefulObject = $factory->create([...]); // [...] are constructor parameters of \Vendor\Namespace\StatefulObject
var_dump(get_class($statefulObject) === StatefulObject::class);
// true
// Same constructor parameters
var_dump($factory->create([...]) !== $factory->create([...]));
// true
// Factory created different instancesFactories of the followings cannot be generated. If you attempt to do so, the code generator will not output anything nor will it throw an exception. Instead, this error will be logged if you specified a logger for the code generator autoloader.
- Non-exist class
- Abstract class
- Trait
- Enum
- Interface without definition (i.e., no preference)
Install the require-dev dependencies and run the following command.
vendor/bin/phpunitIf you like this package or this package helped you, please share and give a ★☆star☆★, it's NOT hard!