wubinworks/php-di-code-generator

Adds automatic code generation feature to PHP-DI. No need to write Factories for stateful objects anymore.

Maintainers

Package info

github.com/wubinworks/php-di-code-generator

Homepage

Chat

pkg:composer/wubinworks/php-di-code-generator

Transparency log

Statistics

Installs: 2

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

1.0.0 2026-07-23 07:08 UTC

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 Factories for 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.

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!