wubinworks / php-di-code-generator
Adds automatic code generation feature to PHP-DI. No need to write Factories for stateful objects anymore.
Package info
github.com/wubinworks/php-di-code-generator
pkg:composer/wubinworks/php-di-code-generator
Requires
- laminas/laminas-code: ^3.4.1 || ^4.0
- php-di/php-di: ^6.3.5 || ^7.0
- symfony/filesystem: ^5.4.45 || ^6.0 || ^7.0 || ^8.0
- wubinworks/error-handler: ^1.0
Requires (Dev)
- monolog/monolog: >=2.11.0
- phpunit/phpunit: >=8.5.52
Suggests
- monolog/monolog: Allows logging of the code generator errors.
This package is not auto-updated.
Last update: 2026-07-23 17:02:11 UTC
README
Adds automatic code generation feature to PHP-DI.
Features
- No need to write
Factoriesfor stateful objects anymore.
Requirements
(*)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
Installation
composer require wubinworks/php-di-code-generator
Container setup steps
1. Add definition of the code generator to the container builder
Parameters required for setting up the code generator
codeDirectory
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.
Example setup
... // 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();
2. Register the code generator's autoloader right after building the container
$container->get(\Wubinworks\PHPDICodeGenerator\Code\Generation\Autoloader::class) ->register();
3. Add autoload configuration to root composer.json
Note this step is optional, but is strongly recommended for performance improvement.
... { "autoload": { ... "psr-4": { "": [ ... "generated/code/", ... ] } ... } } ...
How it works
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.
Usage
1. Append Factory suffix
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); // false
2. Generate the Factory class
class 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.
3. Use the generated Factory to create stateful objects
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 instances
What Factories cannot be generated?
Factories 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)
Unit testing
Install the require-dev dependencies and run the following command.
vendor/bin/phpunit
♥
If you like this package or this package helped you, please share and give a ★☆star☆★, it's NOT hard!