Trait BlackFox\Instance adds static methods ::N() и ::I() to the class, performing factory tasks of creating local or global instances of this class.

Dependency Inversion

Often you need to create a class and its instance (dependent), which depends on another class or interface (dependency).
For example the class Users uses public methods of the class MySQL:

<?php class Users { public function GetByID(int $ID) { global $MySQL; return $MySQL->Query("SELECT * FROM users WHERE ID='{$ID}'"); } }

In a this implementation, the class Users becomes impossible to reuse in conjunction with another database. Generally: a dependent class loses its flexibility regarding dependency. To solve this problem, the principle of Dependency Inversion is used, the implementation of which is as follows:

<?php class Users { /**@var Database $Database */ private $Database; public function __constructor(Database $Database) { $this->Database = $Database; } public function GetByID(int $ID) { return $this->Database->Query("SELECT * FROM users WHERE ID='{$ID}'"); } }

Now the class Users can be used in conjunction with many different databases, abiding by the contract described in the class or interface Database.
But in such an implementation, it is not very convenient to instantiate new instances of the dependent class:

<?php $Database = new Database(); $Users = new Users($Database);

To simplify the creation of new instances of dependent classes, you can add trait Instance to your class:

<?php class Users { use \BlackFox\Instance; // ... }

Then two static methods ::N() и ::I() will appear in the dependent class, which will automatically substitute global instances of the required dependencies into the constructor parameters:

<?php // make new local instance $Users = Users::N(); $data = $Users->GetByID(1); // get (or make and get) global instance $data = Users::I()->GetByID(1);

This will retain the ability to locally redefine some or all of the dependencies:

<?php // make another local instance connected to another database $AnotherUsers = Users::N(['Database' => AnotherDatabase::I()]); $data = $AnotherUsers->GetByID(1);

::N() - creating a new instance

Static method ::N() takes a one-dimensional dictionary of constructor parameters as input and returns a new instance of the appropriate class.

<?php class User { use \BlackFox\Instance; public function __construct(Database $Database, int $ID, bool $optional_flag = true) { $this->Database = $Database; $this->ID = $ID; $this->optional_flag = $optional_flag; } } $User1 = User::N(['ID' => 1]); // ok $User2 = User::N(['ID' => 2, 'optional_flag' => false]); // ok $User3 = User::N(['ID' => 3, 'Database' => AnotherDatabase::I()]); // ok $User4 = User::N([]); // error: ID is missing

::I() - return (or create + return) of a global instance

Often a project requires one universal global object (instance), access to which is possible from any part of the code.
The static method once accepts a one-dimensional dictionary of constructor parameters as input, creates a global instance of the appropriate class (if one has not already been created) and returns a link to it.
Recalling the ::I() method with the parameter will throw an error, since a global instance has already been created.
Recalling the ::I() method without parameters will return a link to the global instance.

<?php class Database { use \BlackFox\Instance; public function __construct(array $params) {} public function Query($SQL) {} } Database::I(['params' => $params]); // ok Database::I()->Query($SQL1); // ok Database::I()->Query($SQL2); // ok Database::I(['params' => $params]); // error

Dictionary of parameters

A one-dimensional dictionary of constructor parameters is optional and is processed as follows:

The mapping of the user type to the global instance is as follows:

Global Override Rules

The current class is considered appropriate unless otherwise specified in the configuration of global override rules.
Global override rules is a dictionary described in the 'overrides' key of the configuration array:

<?php return [ // ... 'overrides' => [ 'BlackFox\Engine' => 'Example\Engine', 'BlackFox\Database' => 'BlackFox\MySQL', 'BlackFox\Captcha' => 'BlackFox\CaptchaDriverGoogleRecaptchaV2', 'BlackFox\Users' => 'Example\Users', 'BlackFox\Cache' => 'BlackFox\CacheRedis', ], // ... ]; BlackFox\Engine::I(); // <-- Example\Engine BlackFox\Database::I(); // <-- BlackFox\MySQL BlackFox\Captcha::I(); // <-- BlackFox\CaptchaDriverGoogleRecaptchaV2 BlackFox\Users::I(); // <-- Example\Users BlackFox\Cache::I(); // <-- BlackFox\CacheRedis

It’s worth noting that these rules are used only by the Instance trait methods, which means that it remains possible to create any objects locally using the 'new' keyword.

Method AddOverrides

Global static method ::AddOverrides(array $overrides) allows you to dynamically add or replace override rules.

<?php \BlackFox\Instance::AddOverrides([ 'BlackFox\Cache' => 'BlackFox\CacheRedis', ]);
Ask question