Dependency Injection Container

PHPportalen Forum Index » Tips och Trix
Lägg ett bokmärke på hela tråden
Skapa nytt inlägg   Svara på inlägget
Visa föregående ämne :: Visa nästa ämne  
Startad av: Meddelande
Saurid
Moderator



Medlem i: 5517 dagar
Från: Karlshamn
Status: Offline



#722498
Inlägg Skrivet: 2012-04-11 17:36      Ämne: Dependency Injection Container Citera

Tänkte visa hur man kan använda anonyma funktioner/closures (en funktion som infördes i PHP 5.3) för att skapa en enkel Dependency Injection Container.

En DI-container är ett objekt som håller reda på dina objekts beroenden av andra objekt eller variabler. Du konfigurerar den en gång (i en config-fil eller likande) så att du slipper att fundera över vad som krävs för att skapa objekt senare. Du använder helt enkelt containern för att skapa objekt istället för att använda new.

Den lagrar även den skapade instansen, så att du alltid hämtar samma instans varje gång du anropar den.

Den kombineras lämpligen med en autoloader Smile

container.php
PHP:
1:
<?php
2:
/**
3:
 * Dependency Injection Container / Registry
4:
 * För PHP >= 5.3
5:
 *
6:
 * @author Ola Waljefors
7:
 */
8:
class container
9:
{
10:
    /**
11:
     * $var array Lagrad data
12:
     * @access private
13:
     */
14:
    private $data;
15:
 
16:
    /**
17:
     * Registrera en egenskap
18:
     *
19:
     * @param string $key
20:
     * @param mixed $value
21:
     */
22:
    public function __set ($key$value)
23:
    {
24:
        $this->data[$key] = $value;
25:
    }
26:
 
27:
    /**
28:
     * Returnera en egenskap
29:
     *
30:
     * Om den är en closure anropas den och lagrar ny data innan den returneras
31:
     *
32:
     * @param string $key
33:
     * @return mixed
34:
     */
35:
    public function __get ($key)
36:
    {
37:
        if (is_a ($this->data[$key], 'Closure')) {
38:
            $this->data[$key] = $this->data[$key] ();
39:
        }
40:
        return $this->data[$key];
41:
    }
42:
}
43:
 


__set() fungerar så att om den ser en closure (eller anonym funktion) så lagrar den funktionen, annars lagrar den variabeln/objektet/whatever som en vanlig egenskap.

Om __get() stöter på en closure så kör den funktionen och returnerar svaret, annars returnerar den egenskapen som den är.

Så hur använda den?

För att lagra och hämta tex strängar gör du så här:

PHP:
1:
 $c = new container ();
2:
 
3:
$c->db_engine   'mysql';
4:
$c->db_host     'localhost';
5:
$c->db_name     'wordpress';
6:
$c->db_user     'root';
7:
$c->db_password ''


För att använda dig av variablerna använder du helt enkelt:
PHP:
1:
 echo $c->db_engine


För att konfigurera ett enkelt objekt utan argument gör du så här:
PHP:
1:
 $c->mittObjekt = function () use ($c) {
2:
    return new mittObjekt ();
3:
}; 


När du sedan ska hämta objektet så kommer den anonyma funktionen att köras, det skapade objektet lagras i containern och returneras så att du kan börja använda det.
PHP:
1:
 $c->mittObjekt


Om du samtidigt vill köra en av objektets metoder kan du göra det också (utan att behöva köra raden ovan):
PHP:
1:
 $c->mittObjekt->metod(); 


Om du ska konfigurera ett andra objekt som använder det första som första argument så gör du följande:
PHP:
1:
 $c->mittAndraObjekt = function () use ($c) {
2:
    return new mittAndraObjekt ($c->mittObjekt);
3:
}; 

När du nu ska hämta objektet så hämtar den helt enkelt alla beroenden rekursivt så att alla objekt skapas upp automatiskt (i detta fallet mittAndraObjekt och mittObjekt). Om något av de ingående objekten redan har skapats upp så används dem. Bra va? Wink

Ett sista exempel. Om du ska konfigurera ett PDO-objekt med hjälp av variablerna jag visade högst upp ibland mina exempel så kan du göra så här:
PHP:
1:
 $c->pdo = function () use ($c) {
2:
    $dsn sprintf ('%s:dbname=%s;host=%s'$c->db_engine$c->db_name$c->db_host);
3:
    return new PDO ($dsn$c->db_user$c->db_password);
4:
}; 


Frågor på det? Laughing

Senast ändrad av Saurid den 2012-04-15 00:34, ändrad totalt 1 gång
 

_________________
waljefors.se :: waeke.se :: GitHub :: SoundCloud
Till toppen på sidan
Visa användarprofil Skicka privat meddelande Besök användarens hemsida
intedinmamma



Medlem i: 3633 dagar
Från: Göteborg
Status: Offline



#722530
Inlägg Skrivet: 2012-04-12 08:22      Ämne: Citera

Det känns som en enklare version utav Pimple. Smile

För dom som är intresserade av att lära sig mer om Dependency Injection så finns det en bra genomgång här.
 

_________________
Statistiskt sett? Kanske.
Till toppen på sidan
Visa användarprofil Skicka privat meddelande
Saurid
Moderator



Medlem i: 5517 dagar
Från: Karlshamn
Status: Offline



#722534
Inlägg Skrivet: 2012-04-12 10:40      Ämne: Citera

intedinmamma skrev:
Det känns som en enklare version utav Pimple. Smile

Det är nog ganska absolut vad det är. Jag är en frekvent besökare på Fabiens blogg och Symfonys sidor, jag gillar helt enkelt det de producerar.

Men för att hindra motståndet mot att ladda ner och läsa engelska kommentarer så har jag gjort en mycket enkel variant, som du säger Smile
 

_________________
waljefors.se :: waeke.se :: GitHub :: SoundCloud
Till toppen på sidan
Visa användarprofil Skicka privat meddelande Besök användarens hemsida
md2perpe
Ex-Moderator



Medlem i: 5991 dagar
Från: Hallonbergen, Kungsbodarna
Status: Offline



#722552
Inlägg Skrivet: 2012-04-12 13:45      Ämne: Citera

Fabien har gjort en ännu mindre: Twittee
 

_________________
6 + sqrt(64) = 10
Till toppen på sidan
Visa användarprofil Skicka privat meddelande
Saurid
Moderator



Medlem i: 5517 dagar
Från: Karlshamn
Status: Offline



#722612
Inlägg Skrivet: 2012-04-15 00:43      Ämne: Citera

md2perpe skrev:
Fabien har gjort en ännu mindre: Twittee

Den är också fin! Men den returnerar alltid en ny instans av klasserna, vilket inte jag vill Smile

Har för övrigt uppdaterat/förenklat en del. Har flyttat villkoret för closures till __get() och på det viset kunnat ta bort en variabel (ersattes båda med $data). Villkoret är förenklat genom att bara använda is_a(), som inte ger en varning om man inte testar mot ett objekt.
 

_________________
waljefors.se :: waeke.se :: GitHub :: SoundCloud
Till toppen på sidan
Visa användarprofil Skicka privat meddelande Besök användarens hemsida
md2perpe
Ex-Moderator



Medlem i: 5991 dagar
Från: Hallonbergen, Kungsbodarna
Status: Offline



#722613
Inlägg Skrivet: 2012-04-15 00:54      Ämne: Citera

Saurid skrev:
Den är också fin! Men den returnerar alltid en ny instans av klasserna, vilket inte jag vill Smile

Det gör den väl inte? Följande borde väl fungera och alltid returnera samma instans?

PHP:
1:
 $c->my_singleton = function ($c) {
2:
    static $the_singleton;
3:
 
4:
    if (is_null($the_singleton)) {
5:
        $the_singleton = new MySingleton(...);
6:
    }
7:
 
8:
    return $the_singleton;
9:
}; 
 

_________________
6 + sqrt(64) = 10
Till toppen på sidan
Visa användarprofil Skicka privat meddelande
intedinmamma



Medlem i: 3633 dagar
Från: Göteborg
Status: Offline



#722614
Inlägg Skrivet: 2012-04-15 01:33      Ämne: Citera

Singleton-funktion finns redan i Pimple. Smile
PHP:
1:
 $container['singleton'] = $container->share(function($c) { return new Whatever(); }); 
 

_________________
Statistiskt sett? Kanske.
Till toppen på sidan
Visa användarprofil Skicka privat meddelande
Saurid
Moderator



Medlem i: 5517 dagar
Från: Karlshamn
Status: Offline



#722674
Inlägg Skrivet: 2012-04-15 22:19      Ämne: Citera

Så sant, det finns ju sätt att lagra instanser! Jag blandade nog ihop med någon annan DIC Embarassed

EDIT: Vilket jag återigen gjorde. Pimple stödjer delade instanser rakt av, medan Twittee kräver lite trixande i closuren. Smile
 

_________________
waljefors.se :: waeke.se :: GitHub :: SoundCloud
Till toppen på sidan
Visa användarprofil Skicka privat meddelande Besök användarens hemsida
fichhunter



Medlem i: 4694 dagar

Status: Offline



#723706
Inlägg Skrivet: 2012-05-24 20:52      Ämne: Citera

Är det fel tänk att skapa ett objekt och sedan spara den?

$container['test'] = $test; //Då är test ett object. Använder Pimple.

Tanken är att jag ska ha en container objekt som håller all information, och objekt jag behöver, alla objekt intitieras dock i en fil som inkluderas, men för att sen injektera in dem i andra klasser etc, används då dependency inject container...


KOD:
1:
 
2:
class Test {
3:
    public static $count = 0;
4:
   
5:
    public function __construct() {
6:
        self::$count++;
7:
    }
8:
   
9:
    public function testthis() {
10:
        echo self::$count;
11:
    }
12:
}
13:
 
14:
$test = new Test();
15:
 
16:
$container = new Pimple();
17:
$container['config'] = $config;
18:
$container['test'] = $test;
19:
 
20:
function test($c) {
21:
    echo $c['test']->testthis();
22:
}
23:
 
24:
test($container);
25:
test($container);
26:
 


Eller bör jag istället skapa objektet i containern, dvs, o använda share () för att få ett singleton objekt?
 
Till toppen på sidan
Visa användarprofil Skicka privat meddelande
md2perpe
Ex-Moderator



Medlem i: 5991 dagar
Från: Hallonbergen, Kungsbodarna
Status: Offline



#723756
Inlägg Skrivet: 2012-05-26 21:28      Ämne: Citera

Det behöver inte vara fel att populera containern "utifrån" i stället för att den populerar sig själv on demand.

Däremot är jag litet tveksam till injektion av containern (så som du gör i funktionen test()). För att det skall vara enkelt för testaren måste man då vara noga med att dokumentera vad containern måste tillhandahålla.
 

_________________
6 + sqrt(64) = 10
Till toppen på sidan
Visa användarprofil Skicka privat meddelande
fichhunter



Medlem i: 4694 dagar

Status: Offline



#728276
Inlägg Skrivet: 2012-12-08 14:09      Ämne: Citera

Hur menar du?

Ska jag injektera $container['test'] istället i funktionen test()?
 
Till toppen på sidan
Visa användarprofil Skicka privat meddelande
Visa tidigare inlägg:   
Skapa nytt inlägg   Svara på inlägget
PHPportalen Forum Index » Tips och Trix
Hoppa till:  
Du kan inte skapa nya inlägg i det här forumet
Du kan inte svara på inlägg i det här forumet
Du kan inte ändra dina inlägg i det här forumet
Du kan inte ta bort dina inlägg i det här forumet
Du kan inte rösta i det här forumet
Du kan inte bifoga filer i detta forum
Du kan inte ladda ner filer från detta forum
Kontakta oss på adressen: info@phpportalen.net
Webbplatsen bygger i grunden på phpBB © 2001, 2002 phpBB Group

Modifieringar har senare gjorts i systemet av PHPportalen
Sid och logotypdesign skapad av Daren Jularic