{"id":13409503,"url":"https://github.com/rdlowrey/auryn","last_synced_at":"2026-03-27T02:44:24.689Z","repository":{"id":4876414,"uuid":"6031624","full_name":"rdlowrey/auryn","owner":"rdlowrey","description":"IoC Dependency Injector","archived":false,"fork":false,"pushed_at":"2023-05-23T10:08:25.000Z","size":705,"stargazers_count":724,"open_issues_count":3,"forks_count":65,"subscribers_count":30,"default_branch":"master","last_synced_at":"2024-09-07T20:08:18.325Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"gdi2290/angular-d3","license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rdlowrey.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2012-10-01T15:10:47.000Z","updated_at":"2024-08-16T10:33:01.000Z","dependencies_parsed_at":"2023-07-05T17:00:52.657Z","dependency_job_id":null,"html_url":"https://github.com/rdlowrey/auryn","commit_stats":{"total_commits":295,"total_committers":34,"mean_commits":8.676470588235293,"dds":0.7491525423728813,"last_synced_commit":"8a57ccb26afdfb3ce2a7214c35d43cec554d38ee"},"previous_names":[],"tags_count":45,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rdlowrey%2Fauryn","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rdlowrey%2Fauryn/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rdlowrey%2Fauryn/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rdlowrey%2Fauryn/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rdlowrey","download_url":"https://codeload.github.com/rdlowrey/auryn/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243593424,"owners_count":20316183,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-30T20:01:01.432Z","updated_at":"2025-12-16T00:35:56.240Z","avatar_url":"https://github.com/rdlowrey.png","language":"PHP","funding_links":[],"categories":["PHP"],"sub_categories":[],"readme":"# auryn [![Build Status](https://travis-ci.org/rdlowrey/auryn.svg?branch=master)](https://travis-ci.org/rdlowrey/auryn)\n\nauryn is a recursive dependency injector. Use auryn to bootstrap and wire together\nS.O.L.I.D., object-oriented PHP applications.\n\n##### How It Works\n\nAmong other things, auryn recursively instantiates class dependencies based on the parameter\ntype-hints specified in class constructor signatures. This requires the use of Reflection. You may\nhave heard that \"reflection is slow\". Let's clear something up: *anything* can be \"slow\" if you're\ndoing it wrong. Reflection is an order of magnitude faster than disk access and several orders of\nmagnitude faster than retrieving information (for example) from a remote database. Additionally,\neach reflection offers the opportunity to cache the results if you're worried about speed. auryn\ncaches any reflections it generates to minimize the potential performance impact.\n\n\u003e auryn **is NOT** a Service Locator. DO NOT turn it into one by passing the injector into your\n\u003e application classes. Service Locator is an anti-pattern; it hides class dependencies, makes code\n\u003e more difficult to maintain and makes a liar of your API! You should *only* use an injector for\n\u003e wiring together the disparate parts of your application during your bootstrap phase.\n\n## The Guide\n\n**Basic Usage**\n\n* [Basic Instantiation](#basic-instantiation)\n* [Injection Definitions](#injection-definitions)\n* [Type-Hint Aliasing](#type-hint-aliasing)\n* [Non-Class Parameters](#non-class-parameters)\n* [Global Parameter Definitions](#global-parameter-definitions)\n\n**Advanced Usage**\n\n* [Instance Sharing](#instance-sharing)\n* [Instantiation Delegates](#instantiation-delegates)\n* [Prepares and Setter Injection](#prepares-and-setter-injection)\n* [Injecting for Execution](#injecting-for-execution)\n* [Dependency Resolution](#dependency-resolution)\n\n**Example Use Cases**\n\n* [Avoiding Evil Singletons](#avoiding-evil-singletons)\n* [Application Bootstrapping](#app-bootstrapping)\n\n\n## Requirements and Installation\n\n- auryn requires PHP 5.3 or higher.\n\n#### Installation\n\n###### Github\n\nYou can clone the latest auryn iteration at anytime from the github repository:\n\n```bash\n$ git clone git://github.com/rdlowrey/auryn.git\n```\n\n###### Composer\n\nYou may also use composer to include auryn as a dependency in your projects `composer.json`. The relevant package is `rdlowrey/auryn`.\n\nAlternatively require the package using composer cli:\n\n```bash\ncomposer require rdlowrey/auryn\n```\n\n##### Manual Download\n\nArchived tagged release versions are also available for manual download on the project\n[tags page](https://github.com/rdlowrey/auryn/tags)\n\n\n## Basic Usage\n\nTo start using the injector, simply create a new instance of the `Auryn\\Injector` (\"the Injector\")\nclass:\n\n```php\n\u003c?php\n$injector = new Auryn\\Injector;\n```\n\n### Basic Instantiation\n\nIf a class doesn't specify any dependencies in its constructor signature there's little point in\nusing the Injector to generate it. However, for the sake of completeness consider that you can do\nthe following with equivalent results:\n\n```php\n\u003c?php\n$injector = new Auryn\\Injector;\n$obj1 = new SomeNamespace\\MyClass;\n$obj2 = $injector-\u003emake('SomeNamespace\\MyClass');\n\nvar_dump($obj2 instanceof SomeNamespace\\MyClass); // true\n```\n\n###### Concrete Type-hinted Dependencies\n\nIf a class only asks for concrete dependencies you can use the Injector to inject them without\nspecifying any injection definitions. For example, in the following scenario you can use the\nInjector to automatically provision `MyClass` with the required `SomeDependency` and `AnotherDependency`\nclass instances:\n\n```php\n\u003c?php\nclass SomeDependency {}\n\nclass AnotherDependency {}\n\nclass MyClass {\n    public $dep1;\n    public $dep2;\n    public function __construct(SomeDependency $dep1, AnotherDependency $dep2) {\n        $this-\u003edep1 = $dep1;\n        $this-\u003edep2 = $dep2;\n    }\n}\n\n$injector = new Auryn\\Injector;\n$myObj = $injector-\u003emake('MyClass');\n\nvar_dump($myObj-\u003edep1 instanceof SomeDependency); // true\nvar_dump($myObj-\u003edep2 instanceof AnotherDependency); // true\n```\n\n###### Recursive Dependency Instantiation\n\nOne of the Injector's key attributes is that it recursively traverses class dependency trees to\ninstantiate objects. This is just a fancy way of saying, \"if you instantiate object A which asks for\nobject B, the Injector will instantiate any of object B's dependencies so that B can be instantiated\nand provided to A\". This is perhaps best understood with a simple example. Consider the following\nclasses in which a `Car` asks for `Engine` and the `Engine` class has concrete dependencies of its\nown:\n\n```php\n\u003c?php\nclass Car {\n    private $engine;\n    public function __construct(Engine $engine) {\n        $this-\u003eengine = $engine;\n    }\n}\n\nclass Engine {\n    private $sparkPlug;\n    private $piston;\n    public function __construct(SparkPlug $sparkPlug, Piston $piston) {\n        $this-\u003esparkPlug = $sparkPlug;\n        $this-\u003episton = $piston;\n    }\n}\n\n$injector = new Auryn\\Injector;\n$car = $injector-\u003emake('Car');\nvar_dump($car instanceof Car); // true\n```\n\n### Injection Definitions\n\nYou may have noticed that the previous examples all demonstrated instantiation of classes with\nexplicit, type-hinted, concrete constructor parameters. Obviously, many of your classes won't fit\nthis mold. Some classes will type-hint interfaces and abstract classes. Some will specify scalar\nparameters which offer no possibility of type-hinting in PHP. Still other parameters will be arrays,\netc. In such cases we need to assist the Injector by telling it exactly what we want to inject.\n\n###### Defining Class Names for Constructor Parameters\n\nLet's look at how to provision a class with non-concrete type-hints in its constructor signature.\nConsider the following code in which a `Car` needs an `Engine` and `Engine` is an interface:\n\n```php\n\u003c?php\ninterface Engine {}\n\nclass V8 implements Engine {}\n\nclass Car {\n    private $engine;\n    public function __construct(Engine $engine) {\n        $this-\u003eengine = $engine;\n    }\n}\n```\n\nTo instantiate a `Car` in this case, we simply need to define an injection definition for the class\nahead of time:\n\n```php\n\u003c?php\n$injector = new Auryn\\Injector;\n$injector-\u003edefine('Car', ['engine' =\u003e 'V8']);\n$car = $injector-\u003emake('Car');\n\nvar_dump($car instanceof Car); // true\n```\n\nThe most important points to notice here are:\n\n1. A custom definition is an `array` whose keys match constructor parameter names\n2. The values in the definition array represent the class names to inject for the specified\n   parameter key\n\nBecause the `Car` constructor parameter we needed to define was named `$engine`, our definition\nspecified an `engine` key whose value was the name of the class (`V8`) that we want to inject.\n\nCustom injection definitions are only necessary on a per-parameter basis. For example, in the\nfollowing class we only need to define the injectable class for `$arg2` because `$arg1` specifies a\nconcrete class type-hint:\n\n```php\n\u003c?php\nclass MyClass {\n    private $arg1;\n    private $arg2;\n    public function __construct(SomeConcreteClass $arg1, SomeInterface $arg2) {\n        $this-\u003earg1 = $arg1;\n        $this-\u003earg2 = $arg2;\n    }\n}\n\n$injector = new Auryn\\Injector;\n$injector-\u003edefine('MyClass', ['arg2' =\u003e 'SomeImplementationClass']);\n\n$myObj = $injector-\u003emake('MyClass');\n```\n\n\u003e **NOTE:** Injecting instances where an abstract class is type-hinted works in exactly the same way\nas the above examples for interface type-hints.\n\n###### Using Existing Instances in Injection Definitions\n\nInjection definitions may also specify a pre-existing instance of the requisite class instead of the\nstring class name:\n\n```php\n\u003c?php\ninterface SomeInterface {}\n\nclass SomeImplementation implements SomeInterface {}\n\nclass MyClass {\n    private $dependency;\n    public function __construct(SomeInterface $dependency) {\n        $this-\u003edependency = $dependency;\n    }\n}\n\n$injector = new Auryn\\Injector;\n$dependencyInstance = new SomeImplementation;\n$injector-\u003edefine('MyClass', [':dependency' =\u003e $dependencyInstance]);\n\n$myObj = $injector-\u003emake('MyClass');\n\nvar_dump($myObj instanceof MyClass); // true\n```\n\n\u003e **NOTE:** Since this `define()` call is passing raw values (as evidenced by the colon `:` usage),\nyou can achieve the same result by omitting the array key(s) and relying on parameter order rather\nthan name. Like so: `$injector-\u003edefine('MyClass', [$dependencyInstance]);`\n\n###### Specifying Injection Definitions On the Fly\n\nYou may also specify injection definitions at call-time with `Auryn\\Injector::make`. Consider:\n\n```php\n\u003c?php\ninterface SomeInterface {}\n\nclass SomeImplementationClass implements SomeInterface {}\n\nclass MyClass {\n    private $dependency;\n    public function __construct(SomeInterface $dependency) {\n        $this-\u003edependency = $dependency;\n    }\n}\n\n$injector = new Auryn\\Injector;\n$myObj = $injector-\u003emake('MyClass', ['dependency' =\u003e 'SomeImplementationClass']);\n\nvar_dump($myObj instanceof MyClass); // true\n```\n\nThe above code shows how even though we haven't called  the Injector's `define` method, the\ncall-time specification allows us to instantiate `MyClass`.\n\n\u003e **NOTE:** on-the-fly instantiation definitions will override a pre-defined definition for the\nspecified class, but only in the context of that particular call to `Auryn\\Injector::make`.\n\n### Type-Hint Aliasing\n\nProgramming to interfaces is one of the most useful concepts in object-oriented design (OOD), and\nwell-designed code should type-hint interfaces whenever possible. But does this mean we have to\nassign injection definitions for every class in our application to reap the benefits of abstracted\ndependencies? Thankfully the answer to this question is, \"NO.\"  The Injector accommodates this goal\nby accepting \"aliases\". Consider:\n\n```php\n\u003c?php\ninterface Engine {}\nclass V8 implements Engine {}\nclass Car {\n    private $engine;\n    public function __construct(Engine $engine) {\n        $this-\u003eengine = $engine;\n    }\n}\n\n$injector = new Auryn\\Injector;\n\n// Tell the Injector class to inject an instance of V8 any time\n// it encounters an Engine type-hint\n$injector-\u003ealias('Engine', 'V8');\n\n$car = $injector-\u003emake('Car');\nvar_dump($car instanceof Car); // bool(true)\n```\n\nIn this example we've demonstrated how to specify an alias class for any occurrence of a particular\ninterface or abstract class type-hint. Once an implementation is assigned, the Injector will use it\nto provision any parameter with a matching type-hint.\n\n\u003e **IMPORTANT:** If an injection definition is defined for a parameter covered by an implementation\nassignment, the definition takes precedence over the implementation.\n\n### Non-Class Parameters\n\nAll of the previous examples have demonstrated how the Injector class instantiates parameters based\non type-hints, class name definitions and existing instances. But what happens if we want to inject\na scalar or other non-object variable into a class? First, let's establish the following behavioral\nrule:\n\n\u003e **IMPORTANT:** The Injector assumes all named-parameter definitions are class names by default.\n\nIf you want the Injector to treat a named-parameter definition as a \"raw\" value and not a class name,\nyou must prefix the parameter name in your definition with a colon character `:`. For example,\nconsider the following code in which we tell the Injector to share a `PDO` database connection\ninstance and define its scalar constructor parameters:\n\n```php\n\u003c?php\n$injector = new Auryn\\Injector;\n$injector-\u003eshare('PDO');\n$injector-\u003edefine('PDO', [\n    ':dsn' =\u003e 'mysql:dbname=testdb;host=127.0.0.1',\n    ':username' =\u003e 'dbuser',\n    ':passwd' =\u003e 'dbpass'\n]);\n\n$db = $injector-\u003emake('PDO');\n```\n\nThe colon character preceding the parameter names tells the Injector that the associated values ARE\nNOT class names. If the colons had been omitted above, auryn would attempt to instantiate classes of\nthe names specified in the string and an exception would result. Also, note that we could just as\neasily specified arrays or integers or any other data type in the above definitions. As long as the\nparameter name is prefixed with a `:`, auryn will inject the value directly without attempting to\ninstantiate it.\n\n\u003e **NOTE:** As mentioned previously, since this `define()` call is passing raw values, you may opt to\nassign the values by parameter order rather than name. Since PDO's first three parameters are `$dsn`,\n`$username`, and `$password`, in that order, you could accomplish the same result by leaving out the\narray keys, like so:\n`$injector-\u003edefine('PDO', ['mysql:dbname=testdb;host=127.0.0.1', 'dbuser', 'dbpass']);`\n\n### Global Parameter Definitions\n\nSometimes applications may reuse the same value everywhere. However, it can be a hassle to manually\nspecify definitions for this sort of thing everywhere it might be used in the app. auryn mitigates\nthis problem by exposing the `Injector::defineParam()` method. Consider the following example ...\n\n```php\n\u003c?php\n$myUniversalValue = 42;\n\nclass MyClass {\n    public $myValue;\n    public function __construct($myValue) {\n        $this-\u003emyValue = $myValue;\n    }\n}\n\n$injector = new Auryn\\Injector;\n$injector-\u003edefineParam('myValue', $myUniversalValue);\n$obj = $injector-\u003emake('MyClass');\nvar_dump($obj-\u003emyValue === 42); // bool(true)\n```\n\nBecause we specified a global definition for `myValue`, all parameters that are not in some other\nway defined (as below) that match the specified parameter name are auto-filled with the global value.\nIf a parameter matches any of the following criteria the global value is not used:\n\n- A typehint\n- A predefined injection definition\n- A custom call time definition\n\n\n## Advanced Usage\n\n### Instance Sharing\n\nOne of the more ubiquitous plagues in modern OOP is the Singleton anti-pattern. Coders looking to\nlimit classes to a single instance often fall into the trap of using `static` Singleton\nimplementations for things like configuration classes and database connections. While it's often\nnecessary to prevent multiple instances of a class, the Singleton method spells death to testability\nand should generally be avoided. `Auryn\\Injector` makes sharing class instances across contexts a\ntriviality while allowing maximum testability and API transparency.\n\nLet's consider how a typical problem facing object-oriented web applications is easily solved by\nwiring together your application using auryn. Here, we want to inject a single database connection\ninstance across multiple layers of an application. We have a controller class that asks for a\nDataMapper that requires a `PDO` database connection instance:\n\n```php\n\u003c?php\nclass DataMapper {\n    private $pdo;\n    public function __construct(PDO $pdo) {\n        $this-\u003epdo = $pdo;\n    }\n}\n\nclass MyController {\n    private $mapper;\n    public function __construct(DataMapper $mapper) {\n        $this-\u003emapper = $mapper;\n    }\n}\n\n$db = new PDO('mysql:host=localhost;dbname=mydb', 'user', 'pass');\n\n$injector = new Auryn\\Injector;\n$injector-\u003eshare($db);\n\n$myController = $injector-\u003emake('MyController');\n```\n\nIn the above code, the `DataMapper` instance will be provisioned with the same `PDO` database\nconnection instance we originally shared. This example is contrived and overly simple, but the\nimplication should be clear:\n\n\u003e By sharing an instance of a class, `Auryn\\Injector` will always use that instance when\n\u003e provisioning classes that type-hint the shared class.\n\n###### A Simpler Example\n\nLet's look at a simple proof of concept:\n\n```php\n\u003c?php\nclass Person {\n    public $name = 'John Snow';\n}\n\n$injector = new Auryn\\Injector;\n$injector-\u003eshare('Person');\n\n$person = $injector-\u003emake('Person');\nvar_dump($person-\u003ename); // John Snow\n\n$person-\u003ename = 'Arya Stark';\n\n$anotherPerson = $injector-\u003emake('Person');\nvar_dump($anotherPerson-\u003ename); // Arya Stark\nvar_dump($person === $anotherPerson); // bool(true) because it's the same instance!\n```\n\nDefining an object as shared will store the provisioned instance in the Injector's shared cache and\nall future requests to the provider for an injected instance of that class will return the\noriginally created object. Note that in the above code, we shared the class name (`Person`)\ninstead of an actual instance. Sharing works with either a class name or an instance of a class.\nThe difference is that when you specify a class name, the Injector\nwill cache the shared instance the first time it is asked to create it.\n\n\u003e **NOTE:** Once the Injector caches a shared instance, call-time definitions passed to\n`Auryn\\Injector::make` will have no effect. Once shared, an instance will always be returned for\ninstantiations of its type until the object is un-shared or refreshed:\n\n### Instantiation Delegates\n\nOften factory classes/methods are used to prepare an object for use after instantiation. auryn\nallows you to integrate factories and builders directly into the injection process by specifying\ncallable instantiation delegates on a per-class basis. Let's look at a very basic example to\ndemonstrate the concept of injection delegates:\n\n```php\n\u003c?php\nclass MyComplexClass {\n    public $verification = false;\n    public function doSomethingAfterInstantiation() {\n        $this-\u003everification = true;\n    }\n}\n\n$complexClassFactory = function() {\n    $obj = new MyComplexClass;\n    $obj-\u003edoSomethingAfterInstantiation();\n\n    return $obj;\n};\n\n$injector = new Auryn\\Injector;\n$injector-\u003edelegate('MyComplexClass', $complexClassFactory);\n\n$obj = $injector-\u003emake('MyComplexClass');\nvar_dump($obj-\u003everification); // bool(true)\n```\n\nIn the above code we delegate instantiation of the `MyComplexClass` class to a closure,\n`$complexClassFactory`. Once this delegation is made, the Injector will return the results of the\nspecified closure when asked to instantiate `MyComplexClass`.\n\n###### Available Delegate Types\n\nAny valid PHP callable may be registered as a class instantiation delegate using\n`Auryn\\Injector::delegate`. Additionally you may specify the name of a delegate class that\nspecifies an `__invoke` method and it will be automatically provisioned and have its `__invoke`\nmethod called at delegation time. Instance methods from uninstantiated classes may also be specified\nusing the `['NonStaticClassName', 'factoryMethod']` construction. For example:\n\n```php\n\u003c?php\nclass SomeClassWithDelegatedInstantiation {\n    public $value = 0;\n}\nclass SomeFactoryDependency {}\nclass MyFactory {\n    private $dependency;\n    function __construct(SomeFactoryDependency $dep) {\n        $this-\u003edependency = $dep;\n    }\n    function __invoke() {\n        $obj = new SomeClassWithDelegatedInstantiation;\n        $obj-\u003evalue = 1;\n        return $obj;\n    }\n    function factoryMethod() {\n        $obj = new SomeClassWithDelegatedInstantiation;\n        $obj-\u003evalue = 2;\n        return $obj;\n    }\n}\n\n// Works because MyFactory specifies a magic __invoke method\n$injector-\u003edelegate('SomeClassWithDelegatedInstantiation', 'MyFactory');\n$obj = $injector-\u003emake('SomeClassWithDelegatedInstantiation');\nvar_dump($obj-\u003evalue); // int(1)\n\n// This also works\n$injector-\u003edelegate('SomeClassWithDelegatedInstantiation', 'MyFactory::factoryMethod');\n$obj = $injector-\u003emake('SomeClassWithDelegatedInstantiation');\n$obj = $injector-\u003emake('SomeClassWithDelegatedInstantiation');\nvar_dump($obj-\u003evalue); // int(2)\n```\n\n### Prepares and Setter Injection\n\nConstructor injection is almost always preferable to setter injection. However, some APIs require\nadditional post-instantiation mutations. auryn accommodates these use cases with its\n`Injector::prepare()` method. Users may register any class or interface name for post-instantiation\nmodification. Consider:\n\n```php\n\u003c?php\n\nclass MyClass {\n    public $myProperty = 0;\n}\n\n$injector-\u003eprepare('MyClass', function($myObj, $injector) {\n    $myObj-\u003emyProperty = 42;\n});\n\n$myObj = $injector-\u003emake('MyClass');\nvar_dump($myObj-\u003emyProperty); // int(42)\n```\n\nWhile the above example is contrived, the usefulness should be clear.\n\n\n### Injecting for Execution\n\nIn addition to provisioning class instances using constructors, auryn can also recursively instantiate\nthe parameters of any [valid PHP callable](http://php.net/manual/en/language.types.callable.php).\nThe following examples all work:\n\n```php\n\u003c?php\n$injector = new Auryn\\Injector;\n$injector-\u003eexecute(function(){});\n$injector-\u003eexecute([$objectInstance, 'methodName']);\n$injector-\u003eexecute('globalFunctionName');\n$injector-\u003eexecute('MyStaticClass::myStaticMethod');\n$injector-\u003eexecute(['MyStaticClass', 'myStaticMethod']);\n$injector-\u003eexecute(['MyChildStaticClass', 'parent::myStaticMethod']);\n$injector-\u003eexecute('ClassThatHasMagicInvoke');\n$injector-\u003eexecute($instanceOfClassThatHasMagicInvoke);\n$injector-\u003eexecute('MyClass::myInstanceMethod');\n```\n\nAdditionally, you can pass in the name of a class for a non-static method and the injector will\nautomatically provision an instance of the class (subject to any definitions or shared instances\nalready stored by the injector) before provisioning and invoking the specified method:\n\n```php\n\u003c?php\nclass Dependency {}\nclass AnotherDependency {}\nclass Example {\n    function __construct(Dependency $dep){}\n    function myMethod(AnotherDependency $arg1, $arg2) {\n        return $arg2;\n    }\n}\n\n$injector = new Auryn\\Injector;\n\n// outputs: int(42)\nvar_dump($injector-\u003eexecute('Example::myMethod', $args = [':arg2' =\u003e 42]));\n```\n\n\n### Dependency Resolution\n\n`Auryn\\Injector` resolves dependencies in the following order:\n\n1. If a shared instance exists for the class in question, the shared instance will always be returned\n2. If a delegate callable is assigned for a class, its return result will always be used\n3. If a call-time definition is passed to `Auryn\\Injector::make`, that definition will be used\n4. If a pre-defined definition exists, it will be used\n5. If a dependency is type-hinted, the Injector will recursively instantiate it subject to any implementations or definitions\n6. If no type-hint exists and the parameter has a default value, the default value is injected\n7. If a global parameter value is defined that value is used\n8. Throw an exception because you did something stupid\n\n## Example Use Cases\n\nDependency Injection Containers (DIC) are generally misunderstood in the PHP community. One of the\nprimary culprits is the misuse of such containers in the mainstream application frameworks. Often,\nthese frameworks warp their DICs into Service Locator anti-patterns. This is a shame because a\ngood DIC should be the exact opposite of a Service Locator.\n\n###### auryn Is NOT A Service Locator!\n\nThere's a galaxy of differences between using a DIC to wire together your application versus\npassing the DIC as a dependency to your objects (Service Locator). Service Locator (SL) is an\nanti-pattern -- it hides class dependencies, makes code difficult to maintain and makes a liar of\nyour API.\n\nWhen you pass a SL into your constructors it makes it difficult to determine what the class dependencies\nreally are. A `House` object depends on `Door` and `Window` objects. A `House` object DOES NOT depend\non an instance of `ServiceLocator` regardless of whether the `ServiceLocator` can provide `Door` and\n`Window` objects.\n\nIn real life you wouldn't build a house by transporting the entire hardware store (hopefully) to\nthe construction site so you can access any parts you need. Instead, the foreman (`__construct()`)\nasks for the specific parts that will be needed (`Door` and `Window`) and goes about procuring them.\nYour objects should function in the same way; they should ask only for the specific dependencies\nrequired to do their jobs. Giving the `House` access to the entire hardware store is at best poor\nOOP style and at worst a maintainability nightmare. The takeaway here is this:\n\n\u003e **IMPORTANT:** do not use auryn like a Service Locator!\n\n\n### Avoiding Evil Singletons\n\nA common difficulty in web applications is limiting the number of database connection instances.\nIt's wasteful and slow to open up new connections each time we need to talk to a database.\nUnfortunately, using singletons to limit these instances makes code brittle and hard to test. Let's\nsee how we can use auryn to inject the same `PDO` instance across the entire scope of our application.\n\nSay we have a service class that requires two separate data mappers to persist information to a database:\n\n```php\n\u003c?php\n\nclass HouseMapper {\n    private $pdo;\n    public function __construct(PDO $pdo) {\n        $this-\u003epdo = $pdo;\n    }\n    public function find($houseId) {\n        $query = 'SELECT * FROM houses WHERE houseId = :houseId';\n\n        $stmt = $this-\u003epdo-\u003eprepare($query);\n        $stmt-\u003ebindValue(':houseId', $houseId);\n\n        $stmt-\u003esetFetchMode(PDO::FETCH_CLASS, 'Model\\\\Entities\\\\House');\n        $stmt-\u003eexecute();\n        $house = $stmt-\u003efetch(PDO::FETCH_CLASS);\n\n        if (false === $house) {\n            throw new RecordNotFoundException(\n                'No houses exist for the specified ID'\n            );\n        }\n\n        return $house;\n    }\n\n    // more data mapper methods here ...\n}\n\nclass PersonMapper {\n    private $pdo;\n    public function __construct(PDO $pdo) {\n        $this-\u003epdo = $pdo;\n    }\n    // data mapper methods here\n}\n\nclass SomeService {\n    private $houseMapper;\n    private $personMapper;\n    public function __construct(HouseMapper $hm, PersonMapper $pm) {\n        $this-\u003ehouseMapper = $hm;\n        $this-\u003epersonMapper = $pm;\n    }\n    public function doSomething() {\n        // do something with the mappers\n    }\n}\n```\n\nIn our wiring/bootstrap code, we simply instantiate the `PDO` instance once and share it in the\ncontext of the `Injector`:\n\n```php\n\u003c?php\n$pdo = new PDO('sqlite:some_sqlite_file.db');\n$pdo-\u003esetAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);\n\n$injector = new Auryn\\Injector;\n\n$injector-\u003eshare($pdo);\n$mapper = $injector-\u003emake('SomeService');\n```\n\nIn the above code, the DIC instantiates our service class. More importantly, the data mapper classes\nit generates to do so are injected *with the same database connection instance we originally shared*.\n\nOf course, we don't have to manually instantiate our `PDO` instance. We could just as easily seed\nthe container with a definition for how to create the `PDO` object and let it handle things for us:\n\n```php\n\u003c?php\n$injector-\u003edefine('PDO', [\n    ':dsn' =\u003e 'sqlite:some_sqlite_file.db'\n]);\n$injector-\u003eshare('PDO');\n$service = $injector-\u003emake('SomeService');\n```\n\nIn the above code, the injector will pass the string definition as the `$dsn` argument in the\n`PDO::__construct` method and generate the shared PDO instance automatically only if one of the\nclasses it instantiates requires a `PDO` instance!\n\n\n\n### App-Bootstrapping\n\nDICs should be used to wire together the disparate objects of your application into a cohesive\nfunctional unit (generally at the bootstrap or front-controller stage of the application). One such\nusage provides an elegant solution for one of the thorny problems in object-oriented (OO) web\napplications: how to instantiate classes in a routed environment where the dependencies are not\nknown ahead of time.\n\nConsider the following front controller code whose job is to:\n\n1. Load a list of application routes and pass them to the router\n2. Generate a model of the client's HTTP request\n3. Route the request instance given the application's route list\n4. Instantiate the routed controller and invoke a method appropriate to the HTTP request\n\n```php\n\u003c?php\n\ndefine('CONTROLLER_ROUTES', '/hard/path/to/routes.xml');\n\n$routeLoader = new RouteLoader();\n$routes = $routeLoader-\u003eloadFromXml(CONTROLLER_ROUTES);\n$router = new Router($routes);\n\n$requestDetector = new RequestDetector();\n$request = $requestDetector-\u003edetectFromSuperglobal($_SERVER);\n\n$requestUri = $request-\u003egetUri();\n$requestMethod = strtolower($request-\u003egetMethod());\n\n$injector = new Auryn\\Injector;\n$injector-\u003eshare($request);\n\ntry {\n    if (!$controllerClass = $router-\u003eroute($requestUri, $requestMethod)) {\n        throw new NoRouteMatchException();\n    }\n\n    $controller = $injector-\u003emake($controllerClass);\n    $callableController = array($controller, $requestMethod);\n\n    if (!is_callable($callableController)) {\n        throw new MethodNotAllowedException();\n    } else {\n        $callableController();\n    }\n\n} catch (NoRouteMatchException $e) {\n    // send 404 response\n} catch (MethodNotAllowedException $e) {\n    // send 405 response\n} catch (Exception $e) {\n    // send 500 response\n}\n```\n\nAnd elsewhere we have various controller classes, each of which ask for their own individual\ndependencies:\n\n```php\n\u003c?php\n\nclass WidgetController {\n    private $request;\n    private $mapper;\n    public function __construct(Request $request, WidgetDataMapper $mapper) {\n        $this-\u003erequest = $request;\n        $this-\u003emapper = $mapper;\n    }\n    public function get() {\n        // do something for HTTP GET requests\n    }\n    public function post() {\n        // do something for HTTP POST requests\n    }\n}\n```\n\nIn the above example the auryn DIC allows us to write fully testable, fully OO controllers that ask\nfor their dependencies. Because the DIC recursively instantiates the dependencies of objects it\ncreates we have no need to pass around a Service Locator. Additionally, this example shows how we can\neliminate evil Singletons using the sharing capabilities of the auryn DIC. In the front controller\ncode, we share the request object so that any classes instantiated by the `Auryn\\Injector` that ask\nfor a `Request` will receive the same instance. This feature not only helps eliminate Singletons,\nbut also the need for hard-to-test `static` properties.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frdlowrey%2Fauryn","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frdlowrey%2Fauryn","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frdlowrey%2Fauryn/lists"}