Baike.dev
All toolsAI codingTrendingOpen sourceNewsSubmit
Log in
< Back to tools
A

auryn

> 编程语言
Open source

IoC Dependency Injector

724 stars0 likes0 views
WebsiteGitHub

About

IoC Dependency Injector

auryn

auryn is a recursive dependency injector. Use auryn to bootstrap and wire together S.O.L.I.D., object-oriented PHP applications.

How It Works

Among other things, auryn recursively instantiates class dependencies based on the parameter type-hints specified in class constructor signatures. This requires the use of Reflection. You may have heard that "reflection is slow". Let's clear something up: anything can be "slow" if you're doing it wrong. Reflection is an order of magnitude faster than disk access and several orders of magnitude faster than retrieving information (for example) from a remote database. Additionally, each reflection offers the opportunity to cache the results if you're worried about speed. auryn caches any reflections it generates to minimize the potential performance impact.

auryn is NOT a Service Locator. DO NOT turn it into one by passing the injector into your application classes. Service Locator is an anti-pattern; it hides class dependencies, makes code more difficult to maintain and makes a liar of your API! You should only use an injector for wiring together the disparate parts of your application during your bootstrap phase.

The Guide

Basic Usage

  • Basic Instantiation
  • Injection Definitions
  • Type-Hint Aliasing
  • Non-Class Parameters
  • Global Parameter Definitions

Advanced Usage

  • Instance Sharing
  • Instantiation Delegates
  • Prepares and Setter Injection
  • Injecting for Execution
  • Dependency Resolution

Example Use Cases

  • Avoiding Evil Singletons
  • Application Bootstrapping

Requirements and Installation

  • auryn requires PHP 5.3 or higher.

Installation

Github

You can clone the latest auryn iteration at anytime from the github repository:

$ git clone git://github.com/rdlowrey/auryn.git
Composer

You may also use composer to include auryn as a dependency in your projects composer.json. The relevant package is rdlowrey/auryn.

Alternatively require the package using composer cli:

composer require rdlowrey/auryn
Manual Download

Archived tagged release versions are also available for manual download on the project tags page

Basic Usage

To start using the injector, simply create a new instance of the Auryn\Injector ("the Injector") class:

make('SomeNamespace\MyClass');

var_dump($obj2 instanceof SomeNamespace\MyClass); // true
Concrete Type-hinted Dependencies

If a class only asks for concrete dependencies you can use the Injector to inject them without specifying any injection definitions. For example, in the following scenario you can use the Injector to automatically provision MyClass with the required SomeDependency and AnotherDependency class instances:

dep1 = $dep1;
        $this->dep2 = $dep2;
    }
}

$injector = new Auryn\Injector;
$myObj = $injector->make('MyClass');

var_dump($myObj->dep1 instanceof SomeDependency); // true
var_dump($myObj->dep2 instanceof AnotherDependency); // true
Recursive Dependency Instantiation

One of the Injector's key attributes is that it recursively traverses class dependency trees to instantiate objects. This is just a fancy way of saying, "if you instantiate object A which asks for object B, the Injector will instantiate any of object B's dependencies so that B can be instantiated and provided to A". This is perhaps best understood with a simple example. Consider the following classes in which a Car asks for Engine and the Engine class has concrete dependencies of its own:

engine = $engine;
    }
}

class Engine {
    private $sparkPlug;
    private $piston;
    public function __construct(SparkPlug $sparkPlug, Piston $piston) {
        $this->sparkPlug = $sparkPlug;
        $this->piston = $piston;
    }
}

$injector = new Auryn\Injector;
$car = $injector->make('Car');
var_dump($car instanceof Car); // true

Injection Definitions

You may have noticed that the previous examples all demonstrated instantiation of classes with explicit, type-hinted, concrete constructor parameters. Obviously, many of your classes won't fit this mold. Some classes will type-hint interfaces and abstract classes. Some will specify scalar parameters which offer no possibility of type-hinting in PHP. Still other parameters will be arrays, etc. In such cases we need to assist the Injector by telling it exactly what we want to inject.

Defining Class Names for Constructor Parameters

Let's look at how to provision a class with non-concrete type-hints in its constructor signature. Consider the following code in which a Car needs an Engine and Engine is an interface:

engine = $engine;
    }
}

To instantiate a Car in this case, we simply need to define an injection definition for the class ahead of time:

define('Car', ['engine' => 'V8']);
$car = $injector->make('Car');

var_dump($car instanceof Car); // true

The most important points to notice here are:

  1. A custom definition is an array whose keys match constructor parameter names
  2. The values in the definition array represent the class names to inject for the specified parameter key

Because the Car constructor parameter we needed to define was named $engine, our definition specified an engine key whose value was the name of the class (V8) that we want to inject.

Custom injection definitions are only necessary on a per-parameter basis. For example, in the following class we only need to define the injectable class for $arg2 because $arg1 specifies a concrete class type-hint:

arg1 = $arg1;
        $this->arg2 = $arg2;
    }
}

$injector = new Auryn\Injector;
$injector->define('MyClass', ['arg2' => 'SomeImplementationClass']);

$myObj = $injector->make('MyClass');

NOTE: Injecting instances where an abstract class is type-hinted works in exactly the same way as the above examples for interface type-hints.

Using Existing Instances in Injection Definitions

Injection definitions may also specify a pre-existing instance of the requisite class instead of the string class name:

dependency = $dependency;
    }
}

$injector = new Auryn\Injector;
$dependencyInstance = new SomeImplementation;
$injector->define('MyClass', [':dependency' => $dependencyInstance]);

$myObj = $injector->make('MyClass');

var_dump($myObj instanceof MyClass); // true

NOTE: Since this define() call is passing raw values (as evidenced by the colon : usage), you can achieve the same result by omitting the array key(s) and relying on parameter order rather than name. Like so: $injector->define('MyClass', [$dependencyInstance]);

Specifying Injection Definitions On the Fly

You may also specify injection definitions at call-time with Auryn\Injector::make. Consider:

dependency = $dependency;
    }
}

$injector = new Auryn\Injector;
$myObj = $injector->make('MyClass', ['dependency' => 'SomeImplementationClass']);

var_dump($myObj instanceof MyClass); // true

The above code shows how even though we haven't called the Injector's define method, the call-time specification allows us to instantiate MyClass.

NOTE: on-the-fly instantiation definitions will override a pre-defined definition for the specified class, but only in the context of that particular call to Auryn\Injector::make.

Type-Hint Aliasing

Programming to interfaces is one of the most useful concepts in object-oriented design (OOD), and well-designed code should type-hint interfaces whenever possible. But does this mean we have to assign injection definitions for every class in our application to reap the benefits of abstracted dependencies? Thankfully the answer to this question is, "NO." The Injector accommodates this goal by accepting "aliases". Consider:

engine = $engine;
    }
}

$injector = new Auryn\Injector;

// Tell the Injector class to inject an instance of V8 any time
// it encounters an Engine type-hint
$injector->alias('Engine', 'V8');

$car = $injector->make('Car');
var_dump($car instanceof Car); // bool(true)

In this example we've demonstrated how to specify an alias class for any occurrence of a particular interface or abstract class type-hint. Once an implementation is assigned, the Injector will use it to provision any parameter with a matching type-hint.

IMPORTANT: If an injection definition is defined for a parameter covered by an implementation assignment, the definition takes precedence over the implementation.

Non-Class Parameters

All of the previous examples have demonstrated how the Injector class instantiates parameters based on type-hints, class name definitions and existing instances. But what happens if we want to inject a scalar or other non-object variable into a class? First, let's establish the following behavioral rule:

IMPORTANT: The Injector assumes all named-parameter definitions are class names by default.

If you want the Injector to treat a named-parameter definition as a "raw" value and not a class name, you must prefix the parameter name in your definition with a colon character :. For example, consider the following code in which we tell the Injector to share a PDO database connection instance and define its scalar constructor parameters:

share('PDO');
$injector->define('PDO', [
    ':dsn' => 'mysql:dbname=testdb;host=127.0.0.1',
    ':username' => 'dbuser',
    ':passwd' => 'dbpass'
]);

$db = $injector->make('PDO');

The colon character preceding the parameter names tells the Injector that the associated values ARE NOT class names. If the colons had been omitted above, auryn would attempt to instantiate classes of the names specified in the string and an exception would result. Also, note that we could just as easily specified arrays or integers or any other data type in the above definitions. As long as the parameter name is prefixed with a :, auryn will inject the value directly without attempting to instantiate it.

NOTE: As mentioned previously, since this define() call is passing raw values, you may opt to assign the values by parameter order rather than name. Since PDO's first three parameters are $dsn, $username, and $password, in that order, you could accomplish the same result by leaving out the array keys, like so: $injector->define('PDO', ['mysql:dbname=testdb;host=127.0.0.1', 'dbuser', 'dbpass']);

Global Parameter Definitions

Sometimes applications may reuse the same value everywhere. However, it can be a hassle to manually specify definitions for this sort of thing everywhere it might be used in the app. auryn mitigates this problem by exposing the Injector::defineParam() method. Consider the following example ...

myValue = $myValue;
    }
}

$injector = new Auryn\Injector;
$injector->defineParam('myValue', $myUniversalValue);
$obj = $injector->make('MyClass');
var_dump($obj->myValue === 42); // bool(true)

Because we specified a global definition for myValue, all parameters that are not in some other way defined (as below) that match the specified parameter name are auto-filled with the global value. If a parameter matches any of the following criteria the global value is not used:

  • A typehint
  • A predefined injection definition
  • A custom call time definition

Advanced Usage

Instance Sharing

One of the more ubiquitous plagues in modern OOP is the Singleton anti-pattern. Coders looking to limit classes to a single instance often fall into the trap of using static Singl

Issues· 0 open

View all issuesOpen on GitHub

No open issues yet, or sync has not completed.

> Tags

PHP

No comments yet. Be the first to share.

> Details

PublishedAug 1, 2026
UpdatedSep 17, 2026
Category编程语言
PricingOpen source

> Related tools

T
TypeScript
JavaScript 的超集,为前端与全栈提供静态类型
P
Python
通用编程语言,广泛用于 Web、数据与 AI
G
Go
Google 推出的简洁高效系统语言