first commit
This commit is contained in:
21
wp-content/plugins/sitepress-multilingual-cms/vendor/otgs/auryn/LICENSE
vendored
Normal file
21
wp-content/plugins/sitepress-multilingual-cms/vendor/otgs/auryn/LICENSE
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2014 Daniel Lowrey, Levi Morrison, Dan Ackroyd
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
||||
847
wp-content/plugins/sitepress-multilingual-cms/vendor/otgs/auryn/README.md
vendored
Normal file
847
wp-content/plugins/sitepress-multilingual-cms/vendor/otgs/auryn/README.md
vendored
Normal file
@@ -0,0 +1,847 @@
|
||||
# auryn [](https://travis-ci.org/rdlowrey/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](#basic-instantiation)
|
||||
* [Injection Definitions](#injection-definitions)
|
||||
* [Type-Hint Aliasing](#type-hint-aliasing)
|
||||
* [Non-Class Parameters](#non-class-parameters)
|
||||
* [Global Parameter Definitions](#global-parameter-definitions)
|
||||
|
||||
**Advanced Usage**
|
||||
|
||||
* [Instance Sharing](#instance-sharing)
|
||||
* [Instantiation Delegates](#instantiation-delegates)
|
||||
* [Prepares and Setter Injection](#prepares-and-setter-injection)
|
||||
* [Injecting for Execution](#injecting-for-execution)
|
||||
* [Dependency Resolution](#dependency-resolution)
|
||||
|
||||
**Example Use Cases**
|
||||
|
||||
* [Avoiding Evil Singletons](#avoiding-evil-singletons)
|
||||
* [Application Bootstrapping](#app-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:
|
||||
|
||||
```bash
|
||||
$ 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:
|
||||
|
||||
```bash
|
||||
composer require rdlowrey/auryn
|
||||
```
|
||||
|
||||
##### Manual Download
|
||||
|
||||
Archived tagged release versions are also available for manual download on the project
|
||||
[tags page](https://github.com/rdlowrey/auryn/tags)
|
||||
|
||||
|
||||
## Basic Usage
|
||||
|
||||
To start using the injector, simply create a new instance of the `Auryn\Injector` ("the Injector")
|
||||
class:
|
||||
|
||||
```php
|
||||
<?php
|
||||
$injector = new Auryn\Injector;
|
||||
```
|
||||
|
||||
### Basic Instantiation
|
||||
|
||||
If a class doesn't specify any dependencies in its constructor signature there's little point in
|
||||
using the Injector to generate it. However, for the sake of completeness consider that you can do
|
||||
the following with equivalent results:
|
||||
|
||||
```php
|
||||
<?php
|
||||
$injector = new Auryn\Injector;
|
||||
$obj1 = new SomeNamespace\MyClass;
|
||||
$obj2 = $injector->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:
|
||||
|
||||
```php
|
||||
<?php
|
||||
class SomeDependency {}
|
||||
|
||||
class AnotherDependency {}
|
||||
|
||||
class MyClass {
|
||||
public $dep1;
|
||||
public $dep2;
|
||||
public function __construct(SomeDependency $dep1, AnotherDependency $dep2) {
|
||||
$this->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:
|
||||
|
||||
```php
|
||||
<?php
|
||||
class Car {
|
||||
private $engine;
|
||||
public function __construct(Engine $engine) {
|
||||
$this->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:
|
||||
|
||||
```php
|
||||
<?php
|
||||
interface Engine {}
|
||||
|
||||
class V8 implements Engine {}
|
||||
|
||||
class Car {
|
||||
private $engine;
|
||||
public function __construct(Engine $engine) {
|
||||
$this->engine = $engine;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
To instantiate a `Car` in this case, we simply need to define an injection definition for the class
|
||||
ahead of time:
|
||||
|
||||
```php
|
||||
<?php
|
||||
$injector = new Auryn\Injector;
|
||||
$injector->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:
|
||||
|
||||
```php
|
||||
<?php
|
||||
class MyClass {
|
||||
private $arg1;
|
||||
private $arg2;
|
||||
public function __construct(SomeConcreteClass $arg1, SomeInterface $arg2) {
|
||||
$this->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:
|
||||
|
||||
```php
|
||||
<?php
|
||||
interface SomeInterface {}
|
||||
|
||||
class SomeImplementation implements SomeInterface {}
|
||||
|
||||
class MyClass {
|
||||
private $dependency;
|
||||
public function __construct(SomeInterface $dependency) {
|
||||
$this->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:
|
||||
|
||||
```php
|
||||
<?php
|
||||
interface SomeInterface {}
|
||||
|
||||
class SomeImplementationClass implements SomeInterface {}
|
||||
|
||||
class MyClass {
|
||||
private $dependency;
|
||||
public function __construct(SomeInterface $dependency) {
|
||||
$this->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:
|
||||
|
||||
```php
|
||||
<?php
|
||||
interface Engine {}
|
||||
class V8 implements Engine {}
|
||||
class Car {
|
||||
private $engine;
|
||||
public function __construct(Engine $engine) {
|
||||
$this->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:
|
||||
|
||||
```php
|
||||
<?php
|
||||
$injector = new Auryn\Injector;
|
||||
$injector->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 ...
|
||||
|
||||
```php
|
||||
<?php
|
||||
$myUniversalValue = 42;
|
||||
|
||||
class MyClass {
|
||||
public $myValue;
|
||||
public function __construct($myValue) {
|
||||
$this->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` Singleton
|
||||
implementations for things like configuration classes and database connections. While it's often
|
||||
necessary to prevent multiple instances of a class, the Singleton method spells death to testability
|
||||
and should generally be avoided. `Auryn\Injector` makes sharing class instances across contexts a
|
||||
triviality while allowing maximum testability and API transparency.
|
||||
|
||||
Let's consider how a typical problem facing object-oriented web applications is easily solved by
|
||||
wiring together your application using auryn. Here, we want to inject a single database connection
|
||||
instance across multiple layers of an application. We have a controller class that asks for a
|
||||
DataMapper that requires a `PDO` database connection instance:
|
||||
|
||||
```php
|
||||
<?php
|
||||
class DataMapper {
|
||||
private $pdo;
|
||||
public function __construct(PDO $pdo) {
|
||||
$this->pdo = $pdo;
|
||||
}
|
||||
}
|
||||
|
||||
class MyController {
|
||||
private $mapper;
|
||||
public function __construct(DataMapper $mapper) {
|
||||
$this->mapper = $mapper;
|
||||
}
|
||||
}
|
||||
|
||||
$db = new PDO('mysql:host=localhost;dbname=mydb', 'user', 'pass');
|
||||
|
||||
$injector = new Auryn\Injector;
|
||||
$injector->share($db);
|
||||
|
||||
$myController = $injector->make('MyController');
|
||||
```
|
||||
|
||||
In the above code, the `DataMapper` instance will be provisioned with the same `PDO` database
|
||||
connection instance we originally shared. This example is contrived and overly simple, but the
|
||||
implication should be clear:
|
||||
|
||||
> By sharing an instance of a class, `Auryn\Injector` will always use that instance when
|
||||
> provisioning classes that type-hint the shared class.
|
||||
|
||||
###### A Simpler Example
|
||||
|
||||
Let's look at a simple proof of concept:
|
||||
|
||||
```php
|
||||
<?php
|
||||
class Person {
|
||||
public $name = 'John Snow';
|
||||
}
|
||||
|
||||
$injector = new Auryn\Injector;
|
||||
$injector->share('Person');
|
||||
|
||||
$person = $injector->make('Person');
|
||||
var_dump($person->name); // John Snow
|
||||
|
||||
$person->name = 'Arya Stark';
|
||||
|
||||
$anotherPerson = $injector->make('Person');
|
||||
var_dump($anotherPerson->name); // Arya Stark
|
||||
var_dump($person === $anotherPerson); // bool(true) because it's the same instance!
|
||||
```
|
||||
|
||||
Defining an object as shared will store the provisioned instance in the Injector's shared cache and
|
||||
all future requests to the provider for an injected instance of that class will return the
|
||||
originally created object. Note that in the above code, we shared the class name (`Person`)
|
||||
instead of an actual instance. Sharing works with either a class name or an instance of a class.
|
||||
The difference is that when you specify a class name, the Injector
|
||||
will cache the shared instance the first time it is asked to create it.
|
||||
|
||||
> **NOTE:** Once the Injector caches a shared instance, call-time definitions passed to
|
||||
`Auryn\Injector::make` will have no effect. Once shared, an instance will always be returned for
|
||||
instantiations of its type until the object is un-shared or refreshed:
|
||||
|
||||
### Instantiation Delegates
|
||||
|
||||
Often factory classes/methods are used to prepare an object for use after instantiation. auryn
|
||||
allows you to integrate factories and builders directly into the injection process by specifying
|
||||
callable instantiation delegates on a per-class basis. Let's look at a very basic example to
|
||||
demonstrate the concept of injection delegates:
|
||||
|
||||
```php
|
||||
<?php
|
||||
class MyComplexClass {
|
||||
public $verification = false;
|
||||
public function doSomethingAfterInstantiation() {
|
||||
$this->verification = true;
|
||||
}
|
||||
}
|
||||
|
||||
$complexClassFactory = function() {
|
||||
$obj = new MyComplexClass;
|
||||
$obj->doSomethingAfterInstantiation();
|
||||
|
||||
return $obj;
|
||||
};
|
||||
|
||||
$injector = new Auryn\Injector;
|
||||
$injector->delegate('MyComplexClass', $complexClassFactory);
|
||||
|
||||
$obj = $injector->make('MyComplexClass');
|
||||
var_dump($obj->verification); // bool(true)
|
||||
```
|
||||
|
||||
In the above code we delegate instantiation of the `MyComplexClass` class to a closure,
|
||||
`$complexClassFactory`. Once this delegation is made, the Injector will return the results of the
|
||||
specified closure when asked to instantiate `MyComplexClass`.
|
||||
|
||||
###### Available Delegate Types
|
||||
|
||||
Any valid PHP callable may be registered as a class instantiation delegate using
|
||||
`Auryn\Injector::delegate`. Additionally you may specify the name of a delegate class that
|
||||
specifies an `__invoke` method and it will be automatically provisioned and have its `__invoke`
|
||||
method called at delegation time. Instance methods from uninstantiated classes may also be specified
|
||||
using the `['NonStaticClassName', 'factoryMethod']` construction. For example:
|
||||
|
||||
```php
|
||||
<?php
|
||||
class SomeClassWithDelegatedInstantiation {
|
||||
public $value = 0;
|
||||
}
|
||||
class SomeFactoryDependency {}
|
||||
class MyFactory {
|
||||
private $dependency;
|
||||
function __construct(SomeFactoryDependency $dep) {
|
||||
$this->dependency = $dep;
|
||||
}
|
||||
function __invoke() {
|
||||
$obj = new SomeClassWithDelegatedInstantiation;
|
||||
$obj->value = 1;
|
||||
return $obj;
|
||||
}
|
||||
function factoryMethod() {
|
||||
$obj = new SomeClassWithDelegatedInstantiation;
|
||||
$obj->value = 2;
|
||||
return $obj;
|
||||
}
|
||||
}
|
||||
|
||||
// Works because MyFactory specifies a magic __invoke method
|
||||
$injector->delegate('SomeClassWithDelegatedInstantiation', 'MyFactory');
|
||||
$obj = $injector->make('SomeClassWithDelegatedInstantiation');
|
||||
var_dump($obj->value); // int(1)
|
||||
|
||||
// This also works
|
||||
$injector->delegate('SomeClassWithDelegatedInstantiation', 'MyFactory::factoryMethod');
|
||||
$obj = $injector->make('SomeClassWithDelegatedInstantiation');
|
||||
$obj = $injector->make('SomeClassWithDelegatedInstantiation');
|
||||
var_dump($obj->value); // int(2)
|
||||
```
|
||||
|
||||
### Prepares and Setter Injection
|
||||
|
||||
Constructor injection is almost always preferable to setter injection. However, some APIs require
|
||||
additional post-instantiation mutations. auryn accommodates these use cases with its
|
||||
`Injector::prepare()` method. Users may register any class or interface name for post-instantiation
|
||||
modification. Consider:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
class MyClass {
|
||||
public $myProperty = 0;
|
||||
}
|
||||
|
||||
$injector->prepare('MyClass', function($myObj, $injector) {
|
||||
$myObj->myProperty = 42;
|
||||
});
|
||||
|
||||
$myObj = $injector->make('MyClass');
|
||||
var_dump($myObj->myProperty); // int(42)
|
||||
```
|
||||
|
||||
While the above example is contrived, the usefulness should be clear.
|
||||
|
||||
|
||||
### Injecting for Execution
|
||||
|
||||
In addition to provisioning class instances using constructors, auryn can also recursively instantiate
|
||||
the parameters of any [valid PHP callable](http://php.net/manual/en/language.types.callable.php).
|
||||
The following examples all work:
|
||||
|
||||
```php
|
||||
<?php
|
||||
$injector = new Auryn\Injector;
|
||||
$injector->execute(function(){});
|
||||
$injector->execute([$objectInstance, 'methodName']);
|
||||
$injector->execute('globalFunctionName');
|
||||
$injector->execute('MyStaticClass::myStaticMethod');
|
||||
$injector->execute(['MyStaticClass', 'myStaticMethod']);
|
||||
$injector->execute(['MyChildStaticClass', 'parent::myStaticMethod']);
|
||||
$injector->execute('ClassThatHasMagicInvoke');
|
||||
$injector->execute($instanceOfClassThatHasMagicInvoke);
|
||||
$injector->execute('MyClass::myInstanceMethod');
|
||||
```
|
||||
|
||||
Additionally, you can pass in the name of a class for a non-static method and the injector will
|
||||
automatically provision an instance of the class (subject to any definitions or shared instances
|
||||
already stored by the injector) before provisioning and invoking the specified method:
|
||||
|
||||
```php
|
||||
<?php
|
||||
class Dependency {}
|
||||
class AnotherDependency {}
|
||||
class Example {
|
||||
function __construct(Dependency $dep){}
|
||||
function myMethod(AnotherDependency $arg1, $arg2) {
|
||||
return $arg2;
|
||||
}
|
||||
}
|
||||
|
||||
$injector = new Auryn\Injector;
|
||||
|
||||
// outputs: int(42)
|
||||
var_dump($injector->execute('Example::myMethod', $args = [':arg2' => 42]));
|
||||
```
|
||||
|
||||
|
||||
### Dependency Resolution
|
||||
|
||||
`Auryn\Injector` resolves dependencies in the following order:
|
||||
|
||||
1. If a shared instance exists for the class in question, the shared instance will always be returned
|
||||
2. If a delegate callable is assigned for a class, its return result will always be used
|
||||
3. If a call-time definition is passed to `Auryn\Injector::make`, that definition will be used
|
||||
4. If a pre-defined definition exists, it will be used
|
||||
5. If a dependency is type-hinted, the Injector will recursively instantiate it subject to any implementations or definitions
|
||||
6. If no type-hint exists and the parameter has a default value, the default value is injected
|
||||
7. If a global parameter value is defined that value is used
|
||||
8. Throw an exception because you did something stupid
|
||||
|
||||
## Example Use Cases
|
||||
|
||||
Dependency Injection Containers (DIC) are generally misunderstood in the PHP community. One of the
|
||||
primary culprits is the misuse of such containers in the mainstream application frameworks. Often,
|
||||
these frameworks warp their DICs into Service Locator anti-patterns. This is a shame because a
|
||||
good DIC should be the exact opposite of a Service Locator.
|
||||
|
||||
###### auryn Is NOT A Service Locator!
|
||||
|
||||
There's a galaxy of differences between using a DIC to wire together your application versus
|
||||
passing the DIC as a dependency to your objects (Service Locator). Service Locator (SL) is an
|
||||
anti-pattern -- it hides class dependencies, makes code difficult to maintain and makes a liar of
|
||||
your API.
|
||||
|
||||
When you pass a SL into your constructors it makes it difficult to determine what the class dependencies
|
||||
really are. A `House` object depends on `Door` and `Window` objects. A `House` object DOES NOT depend
|
||||
on an instance of `ServiceLocator` regardless of whether the `ServiceLocator` can provide `Door` and
|
||||
`Window` objects.
|
||||
|
||||
In real life you wouldn't build a house by transporting the entire hardware store (hopefully) to
|
||||
the construction site so you can access any parts you need. Instead, the foreman (`__construct()`)
|
||||
asks for the specific parts that will be needed (`Door` and `Window`) and goes about procuring them.
|
||||
Your objects should function in the same way; they should ask only for the specific dependencies
|
||||
required to do their jobs. Giving the `House` access to the entire hardware store is at best poor
|
||||
OOP style and at worst a maintainability nightmare. The takeaway here is this:
|
||||
|
||||
> **IMPORTANT:** do not use auryn like a Service Locator!
|
||||
|
||||
|
||||
### Avoiding Evil Singletons
|
||||
|
||||
A common difficulty in web applications is limiting the number of database connection instances.
|
||||
It's wasteful and slow to open up new connections each time we need to talk to a database.
|
||||
Unfortunately, using singletons to limit these instances makes code brittle and hard to test. Let's
|
||||
see how we can use auryn to inject the same `PDO` instance across the entire scope of our application.
|
||||
|
||||
Say we have a service class that requires two separate data mappers to persist information to a database:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
class HouseMapper {
|
||||
private $pdo;
|
||||
public function __construct(PDO $pdo) {
|
||||
$this->pdo = $pdo;
|
||||
}
|
||||
public function find($houseId) {
|
||||
$query = 'SELECT * FROM houses WHERE houseId = :houseId';
|
||||
|
||||
$stmt = $this->pdo->prepare($query);
|
||||
$stmt->bindValue(':houseId', $houseId);
|
||||
|
||||
$stmt->setFetchMode(PDO::FETCH_CLASS, 'Model\\Entities\\House');
|
||||
$stmt->execute();
|
||||
$house = $stmt->fetch(PDO::FETCH_CLASS);
|
||||
|
||||
if (false === $house) {
|
||||
throw new RecordNotFoundException(
|
||||
'No houses exist for the specified ID'
|
||||
);
|
||||
}
|
||||
|
||||
return $house;
|
||||
}
|
||||
|
||||
// more data mapper methods here ...
|
||||
}
|
||||
|
||||
class PersonMapper {
|
||||
private $pdo;
|
||||
public function __construct(PDO $pdo) {
|
||||
$this->pdo = $pdo;
|
||||
}
|
||||
// data mapper methods here
|
||||
}
|
||||
|
||||
class SomeService {
|
||||
private $houseMapper;
|
||||
private $personMapper;
|
||||
public function __construct(HouseMapper $hm, PersonMapper $pm) {
|
||||
$this->houseMapper = $hm;
|
||||
$this->personMapper = $pm;
|
||||
}
|
||||
public function doSomething() {
|
||||
// do something with the mappers
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In our wiring/bootstrap code, we simply instantiate the `PDO` instance once and share it in the
|
||||
context of the `Injector`:
|
||||
|
||||
```php
|
||||
<?php
|
||||
$pdo = new PDO('sqlite:some_sqlite_file.db');
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
$injector = new Auryn\Injector;
|
||||
|
||||
$injector->share($pdo);
|
||||
$mapper = $injector->make('SomeService');
|
||||
```
|
||||
|
||||
In the above code, the DIC instantiates our service class. More importantly, the data mapper classes
|
||||
it generates to do so are injected *with the same database connection instance we originally shared*.
|
||||
|
||||
Of course, we don't have to manually instantiate our `PDO` instance. We could just as easily seed
|
||||
the container with a definition for how to create the `PDO` object and let it handle things for us:
|
||||
|
||||
```php
|
||||
<?php
|
||||
$injector->define('PDO', [
|
||||
':dsn' => 'sqlite:some_sqlite_file.db'
|
||||
]);
|
||||
$injector->share('PDO');
|
||||
$service = $injector->make('SomeService');
|
||||
```
|
||||
|
||||
In the above code, the injector will pass the string definition as the `$dsn` argument in the
|
||||
`PDO::__construct` method and generate the shared PDO instance automatically only if one of the
|
||||
classes it instantiates requires a `PDO` instance!
|
||||
|
||||
|
||||
|
||||
### App-Bootstrapping
|
||||
|
||||
DICs should be used to wire together the disparate objects of your application into a cohesive
|
||||
functional unit (generally at the bootstrap or front-controller stage of the application). One such
|
||||
usage provides an elegant solution for one of the thorny problems in object-oriented (OO) web
|
||||
applications: how to instantiate classes in a routed environment where the dependencies are not
|
||||
known ahead of time.
|
||||
|
||||
Consider the following front controller code whose job is to:
|
||||
|
||||
1. Load a list of application routes and pass them to the router
|
||||
2. Generate a model of the client's HTTP request
|
||||
3. Route the request instance given the application's route list
|
||||
4. Instantiate the routed controller and invoke a method appropriate to the HTTP request
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
define('CONTROLLER_ROUTES', '/hard/path/to/routes.xml');
|
||||
|
||||
$routeLoader = new RouteLoader();
|
||||
$routes = $routeLoader->loadFromXml(CONTROLLER_ROUTES);
|
||||
$router = new Router($routes);
|
||||
|
||||
$requestDetector = new RequestDetector();
|
||||
$request = $requestDetector->detectFromSuperglobal($_SERVER);
|
||||
|
||||
$requestUri = $request->getUri();
|
||||
$requestMethod = strtolower($request->getMethod());
|
||||
|
||||
$injector = new Auryn\Injector;
|
||||
$injector->share($request);
|
||||
|
||||
try {
|
||||
if (!$controllerClass = $router->route($requestUri, $requestMethod)) {
|
||||
throw new NoRouteMatchException();
|
||||
}
|
||||
|
||||
$controller = $injector->make($controllerClass);
|
||||
$callableController = array($controller, $requestMethod);
|
||||
|
||||
if (!is_callable($callableController)) {
|
||||
throw new MethodNotAllowedException();
|
||||
} else {
|
||||
$callableController();
|
||||
}
|
||||
|
||||
} catch (NoRouteMatchException $e) {
|
||||
// send 404 response
|
||||
} catch (MethodNotAllowedException $e) {
|
||||
// send 405 response
|
||||
} catch (Exception $e) {
|
||||
// send 500 response
|
||||
}
|
||||
```
|
||||
|
||||
And elsewhere we have various controller classes, each of which ask for their own individual
|
||||
dependencies:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
class WidgetController {
|
||||
private $request;
|
||||
private $mapper;
|
||||
public function __construct(Request $request, WidgetDataMapper $mapper) {
|
||||
$this->request = $request;
|
||||
$this->mapper = $mapper;
|
||||
}
|
||||
public function get() {
|
||||
// do something for HTTP GET requests
|
||||
}
|
||||
public function post() {
|
||||
// do something for HTTP POST requests
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In the above example the auryn DIC allows us to write fully testable, fully OO controllers that ask
|
||||
for their dependencies. Because the DIC recursively instantiates the dependencies of objects it
|
||||
creates we have no need to pass around a Service Locator. Additionally, this example shows how we can
|
||||
eliminate evil Singletons using the sharing capabilities of the auryn DIC. In the front controller
|
||||
code, we share the request object so that any classes instantiated by the `Auryn\Injector` that ask
|
||||
for a `Request` will receive the same instance. This feature not only helps eliminate Singletons,
|
||||
but also the need for hard-to-test `static` properties.
|
||||
37
wp-content/plugins/sitepress-multilingual-cms/vendor/otgs/auryn/examples/delegate_params.php
vendored
Normal file
37
wp-content/plugins/sitepress-multilingual-cms/vendor/otgs/auryn/examples/delegate_params.php
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
require __DIR__ . "/../vendor/autoload.php";
|
||||
|
||||
class A {
|
||||
private $a;
|
||||
private $b;
|
||||
|
||||
public function __construct(stdClass $a, stdClass $b) {
|
||||
$this->a = $a;
|
||||
$this->b = $b;
|
||||
}
|
||||
|
||||
public function print() {
|
||||
print $this->a->foo;
|
||||
print $this->b->foo;
|
||||
print PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
$injector = new WPML\Auryn\Injector;
|
||||
|
||||
$injector->define(A::class, [
|
||||
"+a" => function () {
|
||||
$std = new stdClass;
|
||||
$std->foo = "foo";
|
||||
return $std;
|
||||
},
|
||||
"+b" => function () {
|
||||
$std = new stdClass;
|
||||
$std->foo = "bar";
|
||||
return $std;
|
||||
},
|
||||
]);
|
||||
|
||||
$a = $injector->make(A::class);
|
||||
$a->print();
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
use Auryn\Injector;
|
||||
|
||||
require __DIR__ . "/../vendor/autoload.php";
|
||||
|
||||
$injector = new Injector;
|
||||
|
||||
class A {
|
||||
public $std;
|
||||
|
||||
public function __construct(stdClass $std) {
|
||||
$this->std = $std;
|
||||
}
|
||||
}
|
||||
|
||||
$stdClass = new stdClass;
|
||||
$stdClass->foo = "foobar";
|
||||
|
||||
$a = $injector->make(A::class, [
|
||||
":std" => $stdClass,
|
||||
]);
|
||||
|
||||
print $a->std->foo . PHP_EOL;
|
||||
108
wp-content/plugins/sitepress-multilingual-cms/vendor/otgs/auryn/lib/CachingReflector.php
vendored
Normal file
108
wp-content/plugins/sitepress-multilingual-cms/vendor/otgs/auryn/lib/CachingReflector.php
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Auryn;
|
||||
|
||||
class CachingReflector implements Reflector
|
||||
{
|
||||
const CACHE_KEY_CLASSES = 'auryn.refls.classes.';
|
||||
const CACHE_KEY_CTORS = 'auryn.refls.ctors.';
|
||||
const CACHE_KEY_CTOR_PARAMS = 'auryn.refls.ctor-params.';
|
||||
const CACHE_KEY_FUNCS = 'auryn.refls.funcs.';
|
||||
const CACHE_KEY_METHODS = 'auryn.refls.methods.';
|
||||
|
||||
private $reflector;
|
||||
private $cache;
|
||||
|
||||
public function __construct(Reflector $reflector = null, ReflectionCache $cache = null)
|
||||
{
|
||||
$this->reflector = $reflector ?: new StandardReflector;
|
||||
$this->cache = $cache ?: new ReflectionCacheArray;
|
||||
}
|
||||
|
||||
public function getClass($class)
|
||||
{
|
||||
$cacheKey = self::CACHE_KEY_CLASSES . strtolower($class);
|
||||
|
||||
if (($reflectionClass = $this->cache->fetch($cacheKey)) === false) {
|
||||
$this->cache->store($cacheKey, $reflectionClass = $this->reflector->getClass($class));
|
||||
}
|
||||
|
||||
return $reflectionClass;
|
||||
}
|
||||
|
||||
public function getCtor($class)
|
||||
{
|
||||
$cacheKey = self::CACHE_KEY_CTORS . strtolower($class);
|
||||
|
||||
if (($reflectedCtor = $this->cache->fetch($cacheKey)) === false) {
|
||||
$this->cache->store($cacheKey, $reflectedCtor = $this->reflector->getCtor($class));
|
||||
}
|
||||
|
||||
return $reflectedCtor;
|
||||
}
|
||||
|
||||
public function getCtorParams($class)
|
||||
{
|
||||
$cacheKey = self::CACHE_KEY_CTOR_PARAMS . strtolower($class);
|
||||
|
||||
if (($reflectedCtorParams = $this->cache->fetch($cacheKey)) === false) {
|
||||
$this->cache->store($cacheKey, $reflectedCtorParams = $this->reflector->getCtorParams($class));
|
||||
}
|
||||
|
||||
return $reflectedCtorParams;
|
||||
}
|
||||
|
||||
public function getParamTypeHint(\ReflectionFunctionAbstract $function, \ReflectionParameter $param)
|
||||
{
|
||||
$lowParam = strtolower($param->name);
|
||||
|
||||
if ($function instanceof \ReflectionMethod) {
|
||||
$lowClass = strtolower($function->class);
|
||||
$lowMethod = strtolower($function->name);
|
||||
$paramCacheKey = self::CACHE_KEY_CLASSES . "{$lowClass}.{$lowMethod}.param-{$lowParam}";
|
||||
} else {
|
||||
$lowFunc = strtolower($function->name);
|
||||
$paramCacheKey = (strpos($lowFunc, '{closure}') === false)
|
||||
? self::CACHE_KEY_FUNCS . ".{$lowFunc}.param-{$lowParam}"
|
||||
: null;
|
||||
}
|
||||
|
||||
$typeHint = ($paramCacheKey === null) ? false : $this->cache->fetch($paramCacheKey);
|
||||
|
||||
if (false === $typeHint) {
|
||||
$typeHint = $this->reflector->getParamTypeHint($function, $param);
|
||||
if ($paramCacheKey !== null) {
|
||||
$this->cache->store($paramCacheKey, $typeHint);
|
||||
}
|
||||
}
|
||||
|
||||
return $typeHint;
|
||||
}
|
||||
|
||||
public function getFunction($functionName)
|
||||
{
|
||||
$lowFunc = strtolower($functionName);
|
||||
$cacheKey = self::CACHE_KEY_FUNCS . $lowFunc;
|
||||
|
||||
if (($reflectedFunc = $this->cache->fetch($cacheKey)) === false) {
|
||||
$this->cache->store($cacheKey, $reflectedFunc = $this->reflector->getFunction($functionName));
|
||||
}
|
||||
|
||||
return $reflectedFunc;
|
||||
}
|
||||
|
||||
public function getMethod($classNameOrInstance, $methodName)
|
||||
{
|
||||
$className = is_string($classNameOrInstance)
|
||||
? $classNameOrInstance
|
||||
: get_class($classNameOrInstance);
|
||||
|
||||
$cacheKey = self::CACHE_KEY_METHODS . strtolower($className) . '.' . strtolower($methodName);
|
||||
|
||||
if (($reflectedMethod = $this->cache->fetch($cacheKey)) === false) {
|
||||
$this->cache->store($cacheKey, $reflectedMethod = $this->reflector->getMethod($classNameOrInstance, $methodName));
|
||||
}
|
||||
|
||||
return $reflectedMethod;
|
||||
}
|
||||
}
|
||||
7
wp-content/plugins/sitepress-multilingual-cms/vendor/otgs/auryn/lib/ConfigException.php
vendored
Normal file
7
wp-content/plugins/sitepress-multilingual-cms/vendor/otgs/auryn/lib/ConfigException.php
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Auryn;
|
||||
|
||||
class ConfigException extends InjectorException
|
||||
{
|
||||
}
|
||||
82
wp-content/plugins/sitepress-multilingual-cms/vendor/otgs/auryn/lib/Executable.php
vendored
Normal file
82
wp-content/plugins/sitepress-multilingual-cms/vendor/otgs/auryn/lib/Executable.php
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Auryn;
|
||||
|
||||
class Executable
|
||||
{
|
||||
private $callableReflection;
|
||||
private $invocationObject;
|
||||
private $isInstanceMethod;
|
||||
|
||||
public function __construct(\ReflectionFunctionAbstract $reflFunc, $invocationObject = null)
|
||||
{
|
||||
if ($reflFunc instanceof \ReflectionMethod) {
|
||||
$this->isInstanceMethod = true;
|
||||
$this->setMethodCallable($reflFunc, $invocationObject);
|
||||
} else {
|
||||
$this->isInstanceMethod = false;
|
||||
$this->callableReflection = $reflFunc;
|
||||
}
|
||||
}
|
||||
|
||||
private function setMethodCallable(\ReflectionMethod $reflection, $invocationObject)
|
||||
{
|
||||
if (is_object($invocationObject)) {
|
||||
$this->callableReflection = $reflection;
|
||||
$this->invocationObject = $invocationObject;
|
||||
} elseif ($reflection->isStatic()) {
|
||||
$this->callableReflection = $reflection;
|
||||
} else {
|
||||
throw new \InvalidArgumentException(
|
||||
'ReflectionMethod callables must specify an invocation object'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function __invoke()
|
||||
{
|
||||
$args = func_get_args();
|
||||
$reflection = $this->callableReflection;
|
||||
|
||||
if ($this->isInstanceMethod) {
|
||||
return $reflection->invokeArgs($this->invocationObject, $args);
|
||||
}
|
||||
|
||||
return $this->callableReflection->isClosure()
|
||||
? $this->invokeClosureCompat($reflection, $args)
|
||||
: $reflection->invokeArgs($args);
|
||||
}
|
||||
|
||||
/**
|
||||
* @TODO Remove this extra indirection when 5.3 support is dropped
|
||||
*/
|
||||
private function invokeClosureCompat($reflection, $args)
|
||||
{
|
||||
if (version_compare(PHP_VERSION, '5.4.0') >= 0) {
|
||||
$scope = $reflection->getClosureScopeClass();
|
||||
$closure = \Closure::bind(
|
||||
$reflection->getClosure(),
|
||||
$reflection->getClosureThis(),
|
||||
$scope ? $scope->name : null
|
||||
);
|
||||
return call_user_func_array($closure, $args);
|
||||
} else {
|
||||
return $reflection->invokeArgs($args);
|
||||
}
|
||||
}
|
||||
|
||||
public function getCallableReflection()
|
||||
{
|
||||
return $this->callableReflection;
|
||||
}
|
||||
|
||||
public function getInvocationObject()
|
||||
{
|
||||
return $this->invocationObject;
|
||||
}
|
||||
|
||||
public function isInstanceMethod()
|
||||
{
|
||||
return $this->isInstanceMethod;
|
||||
}
|
||||
}
|
||||
67
wp-content/plugins/sitepress-multilingual-cms/vendor/otgs/auryn/lib/InjectionException.php
vendored
Normal file
67
wp-content/plugins/sitepress-multilingual-cms/vendor/otgs/auryn/lib/InjectionException.php
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Auryn;
|
||||
|
||||
class InjectionException extends InjectorException
|
||||
{
|
||||
public $dependencyChain;
|
||||
|
||||
public function __construct(array $inProgressMakes, $message = "", $code = 0, \Exception $previous = null)
|
||||
{
|
||||
$this->dependencyChain = array_flip($inProgressMakes);
|
||||
ksort($this->dependencyChain);
|
||||
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a human readable version of the invalid callable to the standard 'invalid invokable' message.
|
||||
*/
|
||||
public static function fromInvalidCallable(
|
||||
array $inProgressMakes,
|
||||
$callableOrMethodStr,
|
||||
\Exception $previous = null
|
||||
) {
|
||||
$callableString = null;
|
||||
|
||||
if (is_string($callableOrMethodStr)) {
|
||||
$callableString .= $callableOrMethodStr;
|
||||
} else if (is_array($callableOrMethodStr) &&
|
||||
array_key_exists(0, $callableOrMethodStr) &&
|
||||
array_key_exists(0, $callableOrMethodStr)) {
|
||||
if (is_string($callableOrMethodStr[0]) && is_string($callableOrMethodStr[1])) {
|
||||
$callableString .= $callableOrMethodStr[0].'::'.$callableOrMethodStr[1];
|
||||
} else if (is_object($callableOrMethodStr[0]) && is_string($callableOrMethodStr[1])) {
|
||||
$callableString .= sprintf(
|
||||
"[object(%s), '%s']",
|
||||
get_class($callableOrMethodStr[0]),
|
||||
$callableOrMethodStr[1]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ($callableString) {
|
||||
// Prevent accidental usage of long strings from filling logs.
|
||||
$callableString = substr($callableString, 0, 250);
|
||||
$message = sprintf(
|
||||
"%s. Invalid callable was '%s'",
|
||||
Injector::M_INVOKABLE,
|
||||
$callableString
|
||||
);
|
||||
} else {
|
||||
$message = Injector::M_INVOKABLE;
|
||||
}
|
||||
|
||||
return new self($inProgressMakes, $message, Injector::E_INVOKABLE, $previous);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hierarchy of dependencies that were being created when
|
||||
* the exception occurred.
|
||||
* @return array
|
||||
*/
|
||||
public function getDependencyChain()
|
||||
{
|
||||
return $this->dependencyChain;
|
||||
}
|
||||
}
|
||||
757
wp-content/plugins/sitepress-multilingual-cms/vendor/otgs/auryn/lib/Injector.php
vendored
Normal file
757
wp-content/plugins/sitepress-multilingual-cms/vendor/otgs/auryn/lib/Injector.php
vendored
Normal file
@@ -0,0 +1,757 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Auryn;
|
||||
|
||||
class Injector
|
||||
{
|
||||
const A_RAW = ':';
|
||||
const A_DELEGATE = '+';
|
||||
const A_DEFINE = '@';
|
||||
const I_BINDINGS = 1;
|
||||
const I_DELEGATES = 2;
|
||||
const I_PREPARES = 4;
|
||||
const I_ALIASES = 8;
|
||||
const I_SHARES = 16;
|
||||
const I_ALL = 31;
|
||||
|
||||
const E_NON_EMPTY_STRING_ALIAS = 1;
|
||||
const M_NON_EMPTY_STRING_ALIAS = "Invalid alias: non-empty string required at arguments 1 and 2";
|
||||
const E_SHARED_CANNOT_ALIAS = 2;
|
||||
const M_SHARED_CANNOT_ALIAS = "Cannot alias class %s to %s because it is currently shared";
|
||||
const E_SHARE_ARGUMENT = 3;
|
||||
const M_SHARE_ARGUMENT = "%s::share() requires a string class name or object instance at Argument 1; %s specified";
|
||||
const E_ALIASED_CANNOT_SHARE = 4;
|
||||
const M_ALIASED_CANNOT_SHARE = "Cannot share class %s because it is currently aliased to %s";
|
||||
const E_INVOKABLE = 5;
|
||||
const M_INVOKABLE = "Invalid invokable: callable or provisional string required";
|
||||
const E_NON_PUBLIC_CONSTRUCTOR = 6;
|
||||
const M_NON_PUBLIC_CONSTRUCTOR = "Cannot instantiate protected/private constructor in class %s";
|
||||
const E_NEEDS_DEFINITION = 7;
|
||||
const M_NEEDS_DEFINITION = "Injection definition required for %s %s";
|
||||
const E_MAKE_FAILURE = 8;
|
||||
const M_MAKE_FAILURE = "Could not make %s: %s";
|
||||
const E_UNDEFINED_PARAM = 9;
|
||||
const M_UNDEFINED_PARAM = "No definition available to provision typeless parameter \$%s at position %d in %s()%s";
|
||||
const E_DELEGATE_ARGUMENT = 10;
|
||||
const M_DELEGATE_ARGUMENT = "%s::delegate expects a valid callable or executable class::method string at Argument 2%s";
|
||||
const E_CYCLIC_DEPENDENCY = 11;
|
||||
const M_CYCLIC_DEPENDENCY = "Detected a cyclic dependency while provisioning %s";
|
||||
const E_MAKING_FAILED = 12;
|
||||
const M_MAKING_FAILED = "Making %s did not result in an object, instead result is of type '%s'";
|
||||
|
||||
private $reflector;
|
||||
private $classDefinitions = array();
|
||||
private $paramDefinitions = array();
|
||||
private $aliases = array();
|
||||
private $shares = array();
|
||||
private $prepares = array();
|
||||
private $delegates = array();
|
||||
private $inProgressMakes = array();
|
||||
|
||||
public function __construct(Reflector $reflector = null)
|
||||
{
|
||||
$this->reflector = $reflector ?: new CachingReflector;
|
||||
}
|
||||
|
||||
public function __clone()
|
||||
{
|
||||
$this->inProgressMakes = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Define instantiation directives for the specified class
|
||||
*
|
||||
* @param string $name The class (or alias) whose constructor arguments we wish to define
|
||||
* @param array $args An array mapping parameter names to values/instructions
|
||||
* @return self
|
||||
*/
|
||||
public function define($name, array $args)
|
||||
{
|
||||
list(, $normalizedName) = $this->resolveAlias($name);
|
||||
$this->classDefinitions[$normalizedName] = $args;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign a global default value for all parameters named $paramName
|
||||
*
|
||||
* Global parameter definitions are only used for parameters with no typehint, pre-defined or
|
||||
* call-time definition.
|
||||
*
|
||||
* @param string $paramName The parameter name for which this value applies
|
||||
* @param mixed $value The value to inject for this parameter name
|
||||
* @return self
|
||||
*/
|
||||
public function defineParam($paramName, $value)
|
||||
{
|
||||
$this->paramDefinitions[$paramName] = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define an alias for all occurrences of a given typehint
|
||||
*
|
||||
* Use this method to specify implementation classes for interface and abstract class typehints.
|
||||
*
|
||||
* @param string $original The typehint to replace
|
||||
* @param string $alias The implementation name
|
||||
* @throws ConfigException if any argument is empty or not a string
|
||||
* @return self
|
||||
*/
|
||||
public function alias($original, $alias)
|
||||
{
|
||||
if (empty($original) || !is_string($original)) {
|
||||
throw new ConfigException(
|
||||
self::M_NON_EMPTY_STRING_ALIAS,
|
||||
self::E_NON_EMPTY_STRING_ALIAS
|
||||
);
|
||||
}
|
||||
if (empty($alias) || !is_string($alias)) {
|
||||
throw new ConfigException(
|
||||
self::M_NON_EMPTY_STRING_ALIAS,
|
||||
self::E_NON_EMPTY_STRING_ALIAS
|
||||
);
|
||||
}
|
||||
|
||||
$originalNormalized = $this->normalizeName($original);
|
||||
|
||||
if (isset($this->shares[$originalNormalized])) {
|
||||
throw new ConfigException(
|
||||
sprintf(
|
||||
self::M_SHARED_CANNOT_ALIAS,
|
||||
$this->normalizeName(get_class($this->shares[$originalNormalized])),
|
||||
$alias
|
||||
),
|
||||
self::E_SHARED_CANNOT_ALIAS
|
||||
);
|
||||
}
|
||||
|
||||
if (array_key_exists($originalNormalized, $this->shares)) {
|
||||
$aliasNormalized = $this->normalizeName($alias);
|
||||
$this->shares[$aliasNormalized] = null;
|
||||
unset($this->shares[$originalNormalized]);
|
||||
}
|
||||
|
||||
$this->aliases[$originalNormalized] = $alias;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function normalizeName($className)
|
||||
{
|
||||
return ltrim(strtolower($className), '\\');
|
||||
}
|
||||
|
||||
/**
|
||||
* Share the specified class/instance across the Injector context
|
||||
*
|
||||
* @param mixed $nameOrInstance The class or object to share
|
||||
* @throws ConfigException if $nameOrInstance is not a string or an object
|
||||
* @return self
|
||||
*/
|
||||
public function share($nameOrInstance)
|
||||
{
|
||||
if (is_string($nameOrInstance)) {
|
||||
$this->shareClass($nameOrInstance);
|
||||
} elseif (is_object($nameOrInstance)) {
|
||||
$this->shareInstance($nameOrInstance);
|
||||
} else {
|
||||
throw new ConfigException(
|
||||
sprintf(
|
||||
self::M_SHARE_ARGUMENT,
|
||||
__CLASS__,
|
||||
gettype($nameOrInstance)
|
||||
),
|
||||
self::E_SHARE_ARGUMENT
|
||||
);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function shareClass($nameOrInstance)
|
||||
{
|
||||
list(, $normalizedName) = $this->resolveAlias($nameOrInstance);
|
||||
$this->shares[$normalizedName] = isset($this->shares[$normalizedName])
|
||||
? $this->shares[$normalizedName]
|
||||
: null;
|
||||
}
|
||||
|
||||
private function resolveAlias($name)
|
||||
{
|
||||
$normalizedName = $this->normalizeName($name);
|
||||
if (isset($this->aliases[$normalizedName])) {
|
||||
$name = $this->aliases[$normalizedName];
|
||||
$normalizedName = $this->normalizeName($name);
|
||||
}
|
||||
|
||||
return array($name, $normalizedName);
|
||||
}
|
||||
|
||||
private function shareInstance($obj)
|
||||
{
|
||||
$normalizedName = $this->normalizeName(get_class($obj));
|
||||
if (isset($this->aliases[$normalizedName])) {
|
||||
// You cannot share an instance of a class name that is already aliased
|
||||
throw new ConfigException(
|
||||
sprintf(
|
||||
self::M_ALIASED_CANNOT_SHARE,
|
||||
$normalizedName,
|
||||
$this->aliases[$normalizedName]
|
||||
),
|
||||
self::E_ALIASED_CANNOT_SHARE
|
||||
);
|
||||
}
|
||||
$this->shares[$normalizedName] = $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a prepare callable to modify/prepare objects of type $name after instantiation
|
||||
*
|
||||
* Any callable or provisionable invokable may be specified. Preparers are passed two
|
||||
* arguments: the instantiated object to be mutated and the current Injector instance.
|
||||
*
|
||||
* @param string $name
|
||||
* @param mixed $callableOrMethodStr Any callable or provisionable invokable method
|
||||
* @throws InjectionException if $callableOrMethodStr is not a callable.
|
||||
* See https://github.com/rdlowrey/auryn#injecting-for-execution
|
||||
* @return self
|
||||
*/
|
||||
public function prepare($name, $callableOrMethodStr)
|
||||
{
|
||||
if ($this->isExecutable($callableOrMethodStr) === false) {
|
||||
throw InjectionException::fromInvalidCallable(
|
||||
$this->inProgressMakes,
|
||||
$callableOrMethodStr
|
||||
);
|
||||
}
|
||||
|
||||
list(, $normalizedName) = $this->resolveAlias($name);
|
||||
$this->prepares[$normalizedName] = $callableOrMethodStr;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function isExecutable($exe)
|
||||
{
|
||||
if (is_callable($exe)) {
|
||||
return true;
|
||||
}
|
||||
if (is_string($exe) && method_exists($exe, '__invoke')) {
|
||||
return true;
|
||||
}
|
||||
if (is_array($exe) && isset($exe[0], $exe[1]) && method_exists($exe[0], $exe[1])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegate the creation of $name instances to the specified callable
|
||||
*
|
||||
* @param string $name
|
||||
* @param mixed $callableOrMethodStr Any callable or provisionable invokable method
|
||||
* @throws ConfigException if $callableOrMethodStr is not a callable.
|
||||
* @return self
|
||||
*/
|
||||
public function delegate($name, $callableOrMethodStr)
|
||||
{
|
||||
if ($this->isExecutable($callableOrMethodStr) === false) {
|
||||
$errorDetail = '';
|
||||
if (is_string($callableOrMethodStr)) {
|
||||
$errorDetail = " but received '$callableOrMethodStr'";
|
||||
} elseif (is_array($callableOrMethodStr) &&
|
||||
count($callableOrMethodStr) === 2 &&
|
||||
array_key_exists(0, $callableOrMethodStr) &&
|
||||
array_key_exists(1, $callableOrMethodStr)
|
||||
) {
|
||||
if (is_string($callableOrMethodStr[0]) && is_string($callableOrMethodStr[1])) {
|
||||
$errorDetail = " but received ['".$callableOrMethodStr[0]."', '".$callableOrMethodStr[1]."']";
|
||||
}
|
||||
}
|
||||
throw new ConfigException(
|
||||
sprintf(self::M_DELEGATE_ARGUMENT, __CLASS__, $errorDetail),
|
||||
self::E_DELEGATE_ARGUMENT
|
||||
);
|
||||
}
|
||||
$normalizedName = $this->normalizeName($name);
|
||||
$this->delegates[$normalizedName] = $callableOrMethodStr;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve stored data for the specified definition type
|
||||
*
|
||||
* Exposes introspection of existing binds/delegates/shares/etc for decoration and composition.
|
||||
*
|
||||
* @param string $nameFilter An optional class name filter
|
||||
* @param int $typeFilter A bitmask of Injector::* type constant flags
|
||||
* @return array
|
||||
*/
|
||||
public function inspect($nameFilter = null, $typeFilter = null)
|
||||
{
|
||||
$result = array();
|
||||
$name = $nameFilter ? $this->normalizeName($nameFilter) : null;
|
||||
|
||||
if (empty($typeFilter)) {
|
||||
$typeFilter = self::I_ALL;
|
||||
}
|
||||
|
||||
$types = array(
|
||||
self::I_BINDINGS => "classDefinitions",
|
||||
self::I_DELEGATES => "delegates",
|
||||
self::I_PREPARES => "prepares",
|
||||
self::I_ALIASES => "aliases",
|
||||
self::I_SHARES => "shares"
|
||||
);
|
||||
|
||||
foreach ($types as $type => $source) {
|
||||
if ($typeFilter & $type) {
|
||||
$result[$type] = $this->filter($this->{$source}, $name);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function filter($source, $name)
|
||||
{
|
||||
if (empty($name)) {
|
||||
return $source;
|
||||
} elseif (array_key_exists($name, $source)) {
|
||||
return array($name => $source[$name]);
|
||||
} else {
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate/provision a class instance
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $args
|
||||
* @throws InjectionException if a cyclic gets detected when provisioning
|
||||
* @return mixed
|
||||
*/
|
||||
public function make($name, array $args = array())
|
||||
{
|
||||
list($className, $normalizedClass) = $this->resolveAlias($name);
|
||||
|
||||
if (isset($this->inProgressMakes[$normalizedClass])) {
|
||||
throw new InjectionException(
|
||||
$this->inProgressMakes,
|
||||
sprintf(
|
||||
self::M_CYCLIC_DEPENDENCY,
|
||||
$className
|
||||
),
|
||||
self::E_CYCLIC_DEPENDENCY
|
||||
);
|
||||
}
|
||||
|
||||
$this->inProgressMakes[$normalizedClass] = count($this->inProgressMakes);
|
||||
|
||||
// isset() is used specifically here because classes may be marked as "shared" before an
|
||||
// instance is stored. In these cases the class is "shared," but it has a null value and
|
||||
// instantiation is needed.
|
||||
if (isset($this->shares[$normalizedClass])) {
|
||||
unset($this->inProgressMakes[$normalizedClass]);
|
||||
|
||||
return $this->shares[$normalizedClass];
|
||||
}
|
||||
|
||||
try {
|
||||
if (isset($this->delegates[$normalizedClass])) {
|
||||
$executable = $this->buildExecutable($this->delegates[$normalizedClass]);
|
||||
$reflectionFunction = $executable->getCallableReflection();
|
||||
$args = $this->provisionFuncArgs($reflectionFunction, $args, null, $className);
|
||||
$obj = call_user_func_array(array($executable, '__invoke'), $args);
|
||||
} else {
|
||||
$obj = $this->provisionInstance($className, $normalizedClass, $args);
|
||||
}
|
||||
|
||||
$obj = $this->prepareInstance($obj, $normalizedClass);
|
||||
|
||||
if (array_key_exists($normalizedClass, $this->shares)) {
|
||||
$this->shares[$normalizedClass] = $obj;
|
||||
}
|
||||
|
||||
unset($this->inProgressMakes[$normalizedClass]);
|
||||
}
|
||||
catch (\Throwable $exception) {
|
||||
unset($this->inProgressMakes[$normalizedClass]);
|
||||
throw $exception;
|
||||
}
|
||||
catch (\Exception $exception) {
|
||||
unset($this->inProgressMakes[$normalizedClass]);
|
||||
throw $exception;
|
||||
}
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
private function provisionInstance($className, $normalizedClass, array $definition)
|
||||
{
|
||||
try {
|
||||
$ctor = $this->reflector->getCtor($className);
|
||||
|
||||
if (!$ctor) {
|
||||
$obj = $this->instantiateWithoutCtorParams($className);
|
||||
} elseif (!$ctor->isPublic()) {
|
||||
throw new InjectionException(
|
||||
$this->inProgressMakes,
|
||||
sprintf(self::M_NON_PUBLIC_CONSTRUCTOR, $className),
|
||||
self::E_NON_PUBLIC_CONSTRUCTOR
|
||||
);
|
||||
} elseif ($ctorParams = $this->reflector->getCtorParams($className)) {
|
||||
$reflClass = $this->reflector->getClass($className);
|
||||
$definition = isset($this->classDefinitions[$normalizedClass])
|
||||
? array_replace($this->classDefinitions[$normalizedClass], $definition)
|
||||
: $definition;
|
||||
$args = $this->provisionFuncArgs($ctor, $definition, $ctorParams, $className);
|
||||
$obj = $reflClass->newInstanceArgs($args);
|
||||
} else {
|
||||
$obj = $this->instantiateWithoutCtorParams($className);
|
||||
}
|
||||
|
||||
return $obj;
|
||||
} catch (\ReflectionException $e) {
|
||||
throw new InjectionException(
|
||||
$this->inProgressMakes,
|
||||
sprintf(self::M_MAKE_FAILURE, $className, $e->getMessage()),
|
||||
self::E_MAKE_FAILURE,
|
||||
$e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function instantiateWithoutCtorParams($className)
|
||||
{
|
||||
$reflClass = $this->reflector->getClass($className);
|
||||
|
||||
if (!$reflClass->isInstantiable()) {
|
||||
$type = $reflClass->isInterface() ? 'interface' : 'abstract class';
|
||||
throw new InjectionException(
|
||||
$this->inProgressMakes,
|
||||
sprintf(self::M_NEEDS_DEFINITION, $type, $className),
|
||||
self::E_NEEDS_DEFINITION
|
||||
);
|
||||
}
|
||||
|
||||
return new $className;
|
||||
}
|
||||
|
||||
private function provisionFuncArgs(\ReflectionFunctionAbstract $reflFunc, array $definition, array $reflParams = null, $className = null)
|
||||
{
|
||||
$args = array();
|
||||
|
||||
// @TODO store this in ReflectionStorage
|
||||
if (!isset($reflParams)) {
|
||||
$reflParams = $reflFunc->getParameters();
|
||||
}
|
||||
|
||||
foreach ($reflParams as $i => $reflParam) {
|
||||
$name = $reflParam->name;
|
||||
|
||||
if (isset($definition[$i]) || array_key_exists($i, $definition)) {
|
||||
// indexed arguments take precedence over named parameters
|
||||
$arg = $definition[$i];
|
||||
} elseif (isset($definition[$name]) || array_key_exists($name, $definition)) {
|
||||
// interpret the param as a class name to be instantiated
|
||||
$arg = $this->make($definition[$name]);
|
||||
} elseif (($prefix = self::A_RAW . $name) && (isset($definition[$prefix]) || array_key_exists($prefix, $definition))) {
|
||||
// interpret the param as a raw value to be injected
|
||||
$arg = $definition[$prefix];
|
||||
} elseif (($prefix = self::A_DELEGATE . $name) && isset($definition[$prefix])) {
|
||||
// interpret the param as an invokable delegate
|
||||
$arg = $this->buildArgFromDelegate($name, $definition[$prefix]);
|
||||
} elseif (($prefix = self::A_DEFINE . $name) && isset($definition[$prefix])) {
|
||||
// interpret the param as a class definition
|
||||
$arg = $this->buildArgFromParamDefineArr($definition[$prefix]);
|
||||
} elseif (!$arg = $this->buildArgFromTypeHint($reflFunc, $reflParam)) {
|
||||
$arg = $this->buildArgFromReflParam($reflParam, $className);
|
||||
|
||||
if ($arg === null && PHP_VERSION_ID >= 50600 && $reflParam->isVariadic()) {
|
||||
// buildArgFromReflParam might return null in case the parameter is optional
|
||||
// in case of variadics, the parameter is optional, but null might not be allowed
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$args[] = $arg;
|
||||
}
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
private function buildArgFromParamDefineArr($definition)
|
||||
{
|
||||
if (!is_array($definition)) {
|
||||
throw new InjectionException(
|
||||
$this->inProgressMakes
|
||||
// @TODO Add message
|
||||
);
|
||||
}
|
||||
|
||||
if (!isset($definition[0], $definition[1])) {
|
||||
throw new InjectionException(
|
||||
$this->inProgressMakes
|
||||
// @TODO Add message
|
||||
);
|
||||
}
|
||||
|
||||
list($class, $definition) = $definition;
|
||||
|
||||
return $this->make($class, $definition);
|
||||
}
|
||||
|
||||
private function buildArgFromDelegate($paramName, $callableOrMethodStr)
|
||||
{
|
||||
if ($this->isExecutable($callableOrMethodStr) === false) {
|
||||
throw InjectionException::fromInvalidCallable(
|
||||
$this->inProgressMakes,
|
||||
$callableOrMethodStr
|
||||
);
|
||||
}
|
||||
|
||||
$executable = $this->buildExecutable($callableOrMethodStr);
|
||||
|
||||
return $executable($paramName, $this);
|
||||
}
|
||||
|
||||
private function buildArgFromTypeHint(\ReflectionFunctionAbstract $reflFunc, \ReflectionParameter $reflParam)
|
||||
{
|
||||
$typeHint = $this->reflector->getParamTypeHint($reflFunc, $reflParam);
|
||||
|
||||
if (!$typeHint) {
|
||||
$obj = null;
|
||||
} elseif ($reflParam->isDefaultValueAvailable()) {
|
||||
$normalizedName = $this->normalizeName($typeHint);
|
||||
// Injector has been told explicitly how to make this type
|
||||
if (isset($this->aliases[$normalizedName]) ||
|
||||
isset($this->delegates[$normalizedName]) ||
|
||||
isset($this->shares[$normalizedName])) {
|
||||
$obj = $this->make($typeHint);
|
||||
} else {
|
||||
$obj = $reflParam->getDefaultValue();
|
||||
}
|
||||
} else {
|
||||
$obj = $this->make($typeHint);
|
||||
}
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
private function buildArgFromReflParam(\ReflectionParameter $reflParam, $className = null)
|
||||
{
|
||||
if (array_key_exists($reflParam->name, $this->paramDefinitions)) {
|
||||
$arg = $this->paramDefinitions[$reflParam->name];
|
||||
} elseif ($reflParam->isDefaultValueAvailable()) {
|
||||
$arg = $reflParam->getDefaultValue();
|
||||
} elseif ($reflParam->isOptional()) {
|
||||
// This branch is required to work around PHP bugs where a parameter is optional
|
||||
// but has no default value available through reflection. Specifically, PDO exhibits
|
||||
// this behavior.
|
||||
$arg = null;
|
||||
} else {
|
||||
$reflFunc = $reflParam->getDeclaringFunction();
|
||||
$classDeclare = ($reflFunc instanceof \ReflectionMethod)
|
||||
? " declared in " . $reflFunc->getDeclaringClass()->name . "::"
|
||||
: "";
|
||||
$classWord = ($reflFunc instanceof \ReflectionMethod)
|
||||
? $className . '::'
|
||||
: '';
|
||||
$funcWord = $classWord . $reflFunc->name;
|
||||
|
||||
throw new InjectionException(
|
||||
$this->inProgressMakes,
|
||||
sprintf(
|
||||
self::M_UNDEFINED_PARAM,
|
||||
$reflParam->name,
|
||||
$reflParam->getPosition(),
|
||||
$funcWord,
|
||||
$classDeclare
|
||||
),
|
||||
self::E_UNDEFINED_PARAM
|
||||
);
|
||||
}
|
||||
|
||||
return $arg;
|
||||
}
|
||||
|
||||
private function prepareInstance($obj, $normalizedClass)
|
||||
{
|
||||
if (isset($this->prepares[$normalizedClass])) {
|
||||
$prepare = $this->prepares[$normalizedClass];
|
||||
$executable = $this->buildExecutable($prepare);
|
||||
$result = $executable($obj, $this);
|
||||
if ($result instanceof $normalizedClass) {
|
||||
$obj = $result;
|
||||
}
|
||||
}
|
||||
|
||||
$interfaces = @class_implements($obj);
|
||||
|
||||
if ($interfaces === false) {
|
||||
throw new InjectionException(
|
||||
$this->inProgressMakes,
|
||||
sprintf(
|
||||
self::M_MAKING_FAILED,
|
||||
$normalizedClass,
|
||||
gettype($obj)
|
||||
),
|
||||
self::E_MAKING_FAILED
|
||||
);
|
||||
}
|
||||
|
||||
if (empty($interfaces)) {
|
||||
return $obj;
|
||||
}
|
||||
|
||||
$interfaces = array_flip(array_map(array($this, 'normalizeName'), $interfaces));
|
||||
$prepares = array_intersect_key($this->prepares, $interfaces);
|
||||
foreach ($prepares as $interfaceName => $prepare) {
|
||||
$executable = $this->buildExecutable($prepare);
|
||||
$result = $executable($obj, $this);
|
||||
if ($result instanceof $normalizedClass) {
|
||||
$obj = $result;
|
||||
}
|
||||
}
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke the specified callable or class::method string, provisioning dependencies along the way
|
||||
*
|
||||
* @param mixed $callableOrMethodStr A valid PHP callable or a provisionable ClassName::methodName string
|
||||
* @param array $args Optional array specifying params with which to invoke the provisioned callable
|
||||
* @throws \Auryn\InjectionException
|
||||
* @return mixed Returns the invocation result returned from calling the generated executable
|
||||
*/
|
||||
public function execute($callableOrMethodStr, array $args = array())
|
||||
{
|
||||
list($reflFunc, $invocationObj) = $this->buildExecutableStruct($callableOrMethodStr);
|
||||
$executable = new Executable($reflFunc, $invocationObj);
|
||||
$args = $this->provisionFuncArgs($reflFunc, $args, null, $invocationObj === null ? null : get_class($invocationObj));
|
||||
|
||||
return call_user_func_array(array($executable, '__invoke'), $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provision an Executable instance from any valid callable or class::method string
|
||||
*
|
||||
* @param mixed $callableOrMethodStr A valid PHP callable or a provisionable ClassName::methodName string
|
||||
* @return \Auryn\Executable
|
||||
*/
|
||||
public function buildExecutable($callableOrMethodStr)
|
||||
{
|
||||
try {
|
||||
list($reflFunc, $invocationObj) = $this->buildExecutableStruct($callableOrMethodStr);
|
||||
} catch (\ReflectionException $e) {
|
||||
throw InjectionException::fromInvalidCallable(
|
||||
$this->inProgressMakes,
|
||||
$callableOrMethodStr,
|
||||
$e
|
||||
);
|
||||
}
|
||||
|
||||
return new Executable($reflFunc, $invocationObj);
|
||||
}
|
||||
|
||||
private function buildExecutableStruct($callableOrMethodStr)
|
||||
{
|
||||
if (is_string($callableOrMethodStr)) {
|
||||
$executableStruct = $this->buildExecutableStructFromString($callableOrMethodStr);
|
||||
} elseif ($callableOrMethodStr instanceof \Closure) {
|
||||
$callableRefl = new \ReflectionFunction($callableOrMethodStr);
|
||||
$executableStruct = array($callableRefl, null);
|
||||
} elseif (is_object($callableOrMethodStr) && is_callable($callableOrMethodStr)) {
|
||||
$invocationObj = $callableOrMethodStr;
|
||||
$callableRefl = $this->reflector->getMethod($invocationObj, '__invoke');
|
||||
$executableStruct = array($callableRefl, $invocationObj);
|
||||
} elseif (is_array($callableOrMethodStr)
|
||||
&& isset($callableOrMethodStr[0], $callableOrMethodStr[1])
|
||||
&& count($callableOrMethodStr) === 2
|
||||
) {
|
||||
$executableStruct = $this->buildExecutableStructFromArray($callableOrMethodStr);
|
||||
} else {
|
||||
throw InjectionException::fromInvalidCallable(
|
||||
$this->inProgressMakes,
|
||||
$callableOrMethodStr
|
||||
);
|
||||
}
|
||||
|
||||
return $executableStruct;
|
||||
}
|
||||
|
||||
private function buildExecutableStructFromString($stringExecutable)
|
||||
{
|
||||
if (function_exists($stringExecutable)) {
|
||||
$callableRefl = $this->reflector->getFunction($stringExecutable);
|
||||
$executableStruct = array($callableRefl, null);
|
||||
} elseif (method_exists($stringExecutable, '__invoke')) {
|
||||
$invocationObj = $this->make($stringExecutable);
|
||||
$callableRefl = $this->reflector->getMethod($invocationObj, '__invoke');
|
||||
$executableStruct = array($callableRefl, $invocationObj);
|
||||
} elseif (strpos($stringExecutable, '::') !== false) {
|
||||
list($class, $method) = explode('::', $stringExecutable, 2);
|
||||
$executableStruct = $this->buildStringClassMethodCallable($class, $method);
|
||||
} else {
|
||||
throw InjectionException::fromInvalidCallable(
|
||||
$this->inProgressMakes,
|
||||
$stringExecutable
|
||||
);
|
||||
}
|
||||
|
||||
return $executableStruct;
|
||||
}
|
||||
|
||||
private function buildStringClassMethodCallable($class, $method)
|
||||
{
|
||||
$relativeStaticMethodStartPos = strpos($method, 'parent::');
|
||||
|
||||
if ($relativeStaticMethodStartPos === 0) {
|
||||
$childReflection = $this->reflector->getClass($class);
|
||||
$class = $childReflection->getParentClass()->name;
|
||||
$method = substr($method, $relativeStaticMethodStartPos + 8);
|
||||
}
|
||||
|
||||
list($className, $normalizedClass) = $this->resolveAlias($class);
|
||||
$reflectionMethod = $this->reflector->getMethod($className, $method);
|
||||
|
||||
if ($reflectionMethod->isStatic()) {
|
||||
return array($reflectionMethod, null);
|
||||
}
|
||||
|
||||
$instance = $this->make($className);
|
||||
// If the class was delegated, the instance may not be of the type
|
||||
// $class but some other type. We need to get the reflection on the
|
||||
// actual class to be able to call the method correctly.
|
||||
$reflectionMethod = $this->reflector->getMethod($instance, $method);
|
||||
|
||||
return array($reflectionMethod, $instance);
|
||||
}
|
||||
|
||||
private function buildExecutableStructFromArray($arrayExecutable)
|
||||
{
|
||||
list($classOrObj, $method) = $arrayExecutable;
|
||||
|
||||
if (is_object($classOrObj) && method_exists($classOrObj, $method)) {
|
||||
$callableRefl = $this->reflector->getMethod($classOrObj, $method);
|
||||
$executableStruct = array($callableRefl, $classOrObj);
|
||||
} elseif (is_string($classOrObj)) {
|
||||
$executableStruct = $this->buildStringClassMethodCallable($classOrObj, $method);
|
||||
} else {
|
||||
throw InjectionException::fromInvalidCallable(
|
||||
$this->inProgressMakes,
|
||||
$arrayExecutable
|
||||
);
|
||||
}
|
||||
|
||||
return $executableStruct;
|
||||
}
|
||||
}
|
||||
7
wp-content/plugins/sitepress-multilingual-cms/vendor/otgs/auryn/lib/InjectorException.php
vendored
Normal file
7
wp-content/plugins/sitepress-multilingual-cms/vendor/otgs/auryn/lib/InjectorException.php
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Auryn;
|
||||
|
||||
class InjectorException extends \Exception
|
||||
{
|
||||
}
|
||||
9
wp-content/plugins/sitepress-multilingual-cms/vendor/otgs/auryn/lib/ReflectionCache.php
vendored
Normal file
9
wp-content/plugins/sitepress-multilingual-cms/vendor/otgs/auryn/lib/ReflectionCache.php
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Auryn;
|
||||
|
||||
interface ReflectionCache
|
||||
{
|
||||
public function fetch($key);
|
||||
public function store($key, $data);
|
||||
}
|
||||
41
wp-content/plugins/sitepress-multilingual-cms/vendor/otgs/auryn/lib/ReflectionCacheApc.php
vendored
Normal file
41
wp-content/plugins/sitepress-multilingual-cms/vendor/otgs/auryn/lib/ReflectionCacheApc.php
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Auryn;
|
||||
|
||||
class ReflectionCacheApc implements ReflectionCache
|
||||
{
|
||||
private $localCache;
|
||||
private $timeToLive = 5;
|
||||
|
||||
public function __construct(ReflectionCache $localCache = null)
|
||||
{
|
||||
$this->localCache = $localCache ?: new ReflectionCacheArray;
|
||||
}
|
||||
|
||||
public function setTimeToLive($seconds)
|
||||
{
|
||||
$seconds = (int) $seconds;
|
||||
$this->timeToLive = ($seconds > 0) ? $seconds : $this->timeToLive;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function fetch($key)
|
||||
{
|
||||
$localData = $this->localCache->fetch($key);
|
||||
|
||||
if ($localData != false) {
|
||||
return $localData;
|
||||
} else {
|
||||
$success = null; // stupid by-ref parameter that scrutinizer complains about
|
||||
$data = apc_fetch($key, $success);
|
||||
return $success ? $data : false;
|
||||
}
|
||||
}
|
||||
|
||||
public function store($key, $data)
|
||||
{
|
||||
$this->localCache->store($key, $data);
|
||||
apc_store($key, $data, $this->timeToLive);
|
||||
}
|
||||
}
|
||||
22
wp-content/plugins/sitepress-multilingual-cms/vendor/otgs/auryn/lib/ReflectionCacheArray.php
vendored
Normal file
22
wp-content/plugins/sitepress-multilingual-cms/vendor/otgs/auryn/lib/ReflectionCacheArray.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Auryn;
|
||||
|
||||
class ReflectionCacheArray implements ReflectionCache
|
||||
{
|
||||
private $cache = array();
|
||||
|
||||
public function fetch($key)
|
||||
{
|
||||
// The additional isset() check here improves performance but we also
|
||||
// need array_key_exists() because some cached values === NULL.
|
||||
return (isset($this->cache[$key]) || array_key_exists($key, $this->cache))
|
||||
? $this->cache[$key]
|
||||
: false;
|
||||
}
|
||||
|
||||
public function store($key, $data)
|
||||
{
|
||||
$this->cache[$key] = $data;
|
||||
}
|
||||
}
|
||||
61
wp-content/plugins/sitepress-multilingual-cms/vendor/otgs/auryn/lib/Reflector.php
vendored
Normal file
61
wp-content/plugins/sitepress-multilingual-cms/vendor/otgs/auryn/lib/Reflector.php
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Auryn;
|
||||
|
||||
interface Reflector
|
||||
{
|
||||
/**
|
||||
* Retrieves ReflectionClass instances, caching them for future retrieval
|
||||
*
|
||||
* @param string $class
|
||||
* @return \ReflectionClass
|
||||
*/
|
||||
public function getClass($class);
|
||||
|
||||
/**
|
||||
* Retrieves and caches the constructor (ReflectionMethod) for the specified class
|
||||
*
|
||||
* @param string $class
|
||||
* @return \ReflectionMethod
|
||||
*/
|
||||
public function getCtor($class);
|
||||
|
||||
/**
|
||||
* Retrieves and caches an array of constructor parameters for the given class
|
||||
*
|
||||
* @param string $class
|
||||
* @return \ReflectionParameter[]
|
||||
*/
|
||||
public function getCtorParams($class);
|
||||
|
||||
/**
|
||||
* Retrieves the class type-hint from a given ReflectionParameter
|
||||
*
|
||||
* There is no way to directly access a parameter's type-hint without
|
||||
* instantiating a new ReflectionClass instance and calling its getName()
|
||||
* method. This method stores the results of this approach so that if
|
||||
* the same parameter type-hint or ReflectionClass is needed again we
|
||||
* already have it cached.
|
||||
*
|
||||
* @param \ReflectionFunctionAbstract $function
|
||||
* @param \ReflectionParameter $param
|
||||
*/
|
||||
public function getParamTypeHint(\ReflectionFunctionAbstract $function, \ReflectionParameter $param);
|
||||
|
||||
/**
|
||||
* Retrieves and caches a reflection for the specified function
|
||||
*
|
||||
* @param string $functionName
|
||||
* @return \ReflectionFunction
|
||||
*/
|
||||
public function getFunction($functionName);
|
||||
|
||||
/**
|
||||
* Retrieves and caches a reflection for the specified class method
|
||||
*
|
||||
* @param mixed $classNameOrInstance
|
||||
* @param string $methodName
|
||||
* @return \ReflectionMethod
|
||||
*/
|
||||
public function getMethod($classNameOrInstance, $methodName);
|
||||
}
|
||||
53
wp-content/plugins/sitepress-multilingual-cms/vendor/otgs/auryn/lib/StandardReflector.php
vendored
Normal file
53
wp-content/plugins/sitepress-multilingual-cms/vendor/otgs/auryn/lib/StandardReflector.php
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Auryn;
|
||||
|
||||
class StandardReflector implements Reflector
|
||||
{
|
||||
public function getClass($class)
|
||||
{
|
||||
return new \ReflectionClass($class);
|
||||
}
|
||||
|
||||
public function getCtor($class)
|
||||
{
|
||||
$reflectionClass = new \ReflectionClass($class);
|
||||
|
||||
return $reflectionClass->getConstructor();
|
||||
}
|
||||
|
||||
public function getCtorParams($class)
|
||||
{
|
||||
return ($reflectedCtor = $this->getCtor($class))
|
||||
? $reflectedCtor->getParameters()
|
||||
: null;
|
||||
}
|
||||
|
||||
public function getParamTypeHint( \ReflectionFunctionAbstract $function, \ReflectionParameter $param ) {
|
||||
if ( version_compare( '7.1.0', phpversion(), '<' ) ) {
|
||||
$reflectionClass = $param->getType() && ! $param->getType()->isBuiltin()
|
||||
? new \ReflectionClass( $param->getType()->getName() )
|
||||
: null;
|
||||
} else {
|
||||
$reflectionClass = $param->getClass();
|
||||
}
|
||||
|
||||
return ( $reflectionClass )
|
||||
? $reflectionClass->getName()
|
||||
: null;
|
||||
}
|
||||
|
||||
public function getFunction($functionName)
|
||||
{
|
||||
return new \ReflectionFunction($functionName);
|
||||
}
|
||||
|
||||
public function getMethod($classNameOrInstance, $methodName)
|
||||
{
|
||||
$className = is_string($classNameOrInstance)
|
||||
? $classNameOrInstance
|
||||
: get_class($classNameOrInstance);
|
||||
|
||||
return new \ReflectionMethod($className, $methodName);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user