📜 ⬆️ ⬇️

Implement a DI container in PHP5 using Reflections

This topic is for those who represent what DI is (Dependency Injection) but never thought about “how it works there unutra”.
Read what DI is, for example, here or here.

The goal was not to develop your Production DI framework. I wanted to figure out how to implement this functionality most conveniently ( Phemto , mentioned above, seemed less convenient than, for example, the method from Microsoft Unity )

The implemented version is configured in the code (not via XML, like some other implementations, although this is more convenient for someone).
Each type used must be pre-registered, but it is not necessary to list its arguments, as for example in Phemto - the container itself will find out the types of the constructor arguments through Reflection.
')

The implementation itself (examples below):
<?
class PUnityException extends RuntimeException {

}

class PUnity {

const PUNITY_SINGLETON = 2;
const PUNITY_SIMPLE = 1;

private $data;
private $attributes;
private $singletons;

/**
*
*
* @param string $type
* @param string $concreteInstance
* @param int $attr
*/
public function RegisterType($type, $concreteInstance, $attr = PUnity::PUNITY_SIMPLE) {
// To get exceptions if types are not exists
$typeReflection = new ReflectionClass($type);
$concreteReflection = new ReflectionClass($concreteInstance);

$ this ->data[$type] = $concreteReflection;
$ this ->attributes[$type] = $attr;
}

/**
*
*
* @param string $type
* @return sdtclass
*/
public function Resolve($type) {

if ($ this ->attributes[$type] == PUnity::PUNITY_SINGLETON)
{
$typeReflection = $ this ->data[$type];
try { // May be class is taking care of it's instace by itself?
$getInstance = $typeReflection->getMethod( 'getInstance' ); // Yes, it's a hardcoding...
return $getInstance->invoke( null );
} catch (ReflectionException $e) { }

if (isset($ this ->singletons[$type])) // Try get existing one
return $ this ->singletons[$type];
}

$instance = $ this ->resolver($type); // Resolve type
if ($ this ->attributes[$type] == PUnity::PUNITY_SINGLETON) // Take care of storing the object instance
{
$ this ->singletons[$type] = $instance;
}

return $instance;
}

/**
*
*
* @param string $type
* @return stdclass
*/
private function resolver($type) {
$typeReflection = $ this ->data[$type];
$ctr = $typeReflection->getConstructor();
$args = array();
if ($ctr != null ) // Constructor is defined
{
$ctrParams = $ctr->getParameters();
foreach ($ctrParams as $p) {
$cls = $p->getClass();
if (!isset($ this ->data[$cls->getName()])) // No nothing about needed type
throw new PUnityException( "Type {$cls->getName()} not registered. Use RegisterType first" );
else
array_push($args, $ this ->Resolve($cls->getName()));
}
}
return count($args) ? $typeReflection->newInstanceArgs($args) : $typeReflection->newInstance();
}

}
?>


* This source code was highlighted with Source Code Highlighter .


A simple example of use:
interface ILogger {
public function Logstr($str);
}

class MyLogger implements ILogger {
public function Logstr($str) {
echo "MyLogger: {$str}" ;
}
}

class UsingLogger {
public function __construct(ILogger $myLogger) {
$myLogger->Logstr( " On the move..." );
}
}

$u = new PUnity();
$u->RegisterType( 'ILogger' , 'MyLogger' );
$u->RegisterType( 'UsingLogger' , 'UsingLogger' );

$logger = $u->Resolve( 'UsingLogger' );


* This source code was highlighted with Source Code Highlighter .


But this way you can make singletons:
<?php
interface ILogger {
public function Logstr($str);
}

class MyTrickyLogger implements ILogger {

private $timeCreated;

public function MyTrickyLogger() {
$ this ->timeCreated = time();
}

public function Logstr($str) {
echo "I created at " .date( 'dmY H:i:s .' , $ this ->timeCreated). 'Message: ' .$str. "<br/>\n" ;
}
}

class UsingLogger {
public function __construct(ILogger $myLogger) {
$myLogger->Logstr( " On the move..." );
}
}

$u = new PUnity();
$u->RegisterType( 'ILogger' , 'MyTrickyLogger' , PUnity::PUNITY_SINGLETON);
$u->RegisterType( 'UsingLogger' , 'UsingLogger' );

$logger = $u->Resolve( 'UsingLogger' );
sleep(2);
$logger2 = $u->Resolve( 'UsingLogger' );
?>


* This source code was highlighted with Source Code Highlighter .

Source: https://habr.com/ru/post/86061/


All Articles