Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Factory Laravel Package

yiisoft/factory

A flexible factory for Yii3 that creates objects from class names, definitions, or callables, resolving constructor dependencies through a PSR-11 container. Ideal for configurable services and dependency injection setups.

View on GitHub
Deep Wiki
Context7

Getting Started

yiisoft/factory is a small, focused object factory: give it a PSR-11 container and a class name, and it reflects the constructor, pulls typed dependencies out of the container, and gives you a fully built instance. It is the object-construction layer that sits under yiisoft/di, so you will often use it indirectly — but it is genuinely useful on its own when you need to build objects with runtime arguments that should not be baked into container definitions.

composer require yiisoft/factory

You need a PSR-11 container implementation (yiisoft/di, league/container, or even a hand-written stub). Then:

use Yiisoft\Factory\Factory;

$factory = new Factory($container);

$report = $factory->create(ReportGenerator::class);

ReportGenerator's constructor dependencies are resolved by type from the container; anything the container cannot supply must be provided explicitly or have a default value.

Where to look first:

  1. FactoryInterface::create(string $id, array $parameters = []) — this is the whole public contract.
  2. The README's definitions examples (setDefinitions()), which is where 90% of the real configuration lives.
  3. src/Exception/ — the failure modes (NotFoundException, InvalidConfigException, circular-reference errors) tell you exactly what the factory will refuse to do.

First meaningful use case: a class that needs a mix of injected services and per-call data.

final class InvoicePdf
{
    public function __construct(
        private RendererInterface $renderer,   // from container
        private string $currency,              // runtime
    ) {}
}

$pdf = $factory->create(InvoicePdf::class, ['currency' => 'EUR']);

That's the sweet spot: services from the container, scalars from the call site.

Implementation Patterns

Auto-wiring by type. For every constructor parameter with a class type, the factory asks the container for that type (or resolves it from definitions), recursing as needed. This means most of your services need zero configuration as long as their leaf dependencies are registered or instantiable.

Definitions map. Register interface→implementation mappings and per-class configuration once:

$factory->setDefinitions([
    LoggerInterface::class => FileLogger::class,
    ReportGenerator::class => [
        'class'    => ReportGenerator::class,
        'format'   => 'csv',
        '__construct()' => ['limit' => 500], // explicit constructor args
    ],
]);

The array form is the workhorse: 'class' picks the implementation, remaining keys map to constructor parameter names.

Runtime parameter overrides. Pass a second argument to create() to override constructor arguments by name. Prefer named keys — positional keys silently break the moment someone reorders the constructor. Overrides apply to that object only; they do not mutate the definition.

Callable definitions for anything reflection can't do — static factories, named constructors, private constructors, or values that need imperative setup:

$factory->setDefinitions([
    PDO::class => static fn (ContainerInterface $c) => new PDO($c->get('db.dsn')),
]);

Late binding with references. Yiisoft\Definitions\Reference::to(SomeId::class) defers resolution to the container, and DynamicReference::to(fn () => ...) defers to call time. Use these when a definition's value depends on another service or on environment that isn't known at config-build time.

Integration pattern — inject the interface, not the class. Type-hint FactoryInterface in services that need to build things at runtime, and bind it in your DI config:

FactoryInterface::class => static fn (ContainerInterface $c) => new Factory($c),

This keeps your code testable and avoids coupling to the concrete implementation.

Workflow in a Yii3 app. Before adding a definition to the factory, check config/common/di.php. If the object is a shared service, it belongs in the DI container's singletons; if it is a short-lived object with per-call parameters (a form model, a job payload handler, a report builder), it belongs in the factory.

Testing. Swap in a stub PSR-11 container to assert which dependencies get requested, or use the factory directly to build units under test with fake collaborators injected via definitions.

Gotchas and Tips

  • create() does not cache. Every call reflects and builds a new instance. If you want a singleton, that is yiisoft/di's job — do not use the factory as a service locator in a hot loop.
  • Scalars are never auto-resolved. A string $dsn parameter with no default will throw unless you pass it in create() or the definition. Optional and nullable parameters fall back to defaults, so the failure can be delayed until the one call site that omits the value.
  • Definition arrays vs. plain arrays. An array definition without a 'class' key is ambiguous; be explicit. When in doubt, use ArrayDefinition from yiisoft/definitions rather than raw arrays — you get validation and clearer errors.
  • Circular references are only detected along the factory's own resolution path. A cycle that closes through the container (A → container → B → factory → A) can produce a stack overflow or a confusing container exception instead of the friendly circular-reference error. Keep dependency graphs through the factory shallow.
  • Resolution order matters. Explicit definition wins, then the container, then reflective instantiation of a concrete class. This means adding a container binding can silently shadow what you thought was factory-configured.
  • Positional parameter overrides are a trap. They work, they're documented, and they will break your app the first time a constructor argument is inserted. Always use names.
  • Catch the right exceptions. NotFoundException (class missing / not instantiable), InvalidConfigException (bad definition shape), and NotCallableException (callable definition that isn't callable) are distinct — handle them separately in code paths where misconfiguration should surface as a clear error.
  • Reflection cost is real. If profiling shows the factory on a hot path, memoize at a higher level or move the object into the container as a singleton.
  • Extension point: implement FactoryInterface with a decorator that wraps the real factory to add logging, timing, or metrics — cheaper and safer than subclassing Factory, whose internals are not a stability contract.
  • Debugging tip: when a build fails with an opaque "unable to resolve parameter" error, dump the constructor signature and check whether the failing parameter is a scalar (needs a definition/override) versus a class missing from the container. Those are the only two causes in practice.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource