Dependency Injection и Type Hinting

eddyy93

Registered
Интересува Type Hinting + interface, добра комбинация ли е за ползване, за да получим едно по добро Dependency или има някой по добър вариант, кой според вас е той ? И ако може да напишете едно примерче и да обясните защо така мислите?

Ако нещо не ви допада във структурата на този код също ако може да обясните защо и какво бихте подобрили?

Ето едно просто примерче (използвам примера, който гоогле дават за DI, но в него не обясняват за type hinting - а).

Първият пример е без interface.

Файл: house.php
PHP:
<?php
require 'door.php';
require 'lock.php';

class house {
    
    public function __construct(door $value) {
        echo $value -> GetValue();
    }
    
}

$Door = new door();
$Lock = new lock();


$House = new house($Door);

-----------

Файл: door.php

PHP:
<?php
class door
    {
    public function GetValue() {
       return 'This is door';
    }
}

------------

Файл: lock.php


PHP:
<?php
class lock {
    public function GetValue() {
        return 'This is get lock';
    }
}


При този метод ако сложим обекта Lock, във конструктура на house, то няма как да сработи, все пак използваме type hinting Door


-----------------------

Ето как ще стане чрез интерфейс:

При този вариант, можем да си ползваме и двете инстанции (за разлика от първия метод) и да ги пращаме към конструктура на класа house.


Файл: house.php
PHP:
<?php
require 'iHouse.php';
require 'door.php';
require 'lock.php';


class house {
    
    public function __construct(iHouse $value) {
        echo $value -> GetValue();
       }
  
    
}

$Door = new door();
$Lock = new lock();


$House = new house($Door);

-----------

Файл: door.php

PHP:
<?php

class door implements iHouse
    {
    public function GetValue() {
       return 'This is door';
    }
}

------------

Файл: lock.php


PHP:
<?php

class lock implements iHouse {
    public function GetValue() {
        return 'This is get lock';
    }
    
}

------------

Файл: iHouse.php


PHP:
<?php
interface iHouse {
    public function GetValue();
}
 
Много е добре да си ги правиш така. Можеш винаги да замениш имплементацията (самия клас) и всичко да работи без да се притесняваш класа дали е идентичен
 
Някои също ползват DiC (DI container), но той нещо не ми се вижда много от полза, пък и много замотан става през него кода а и трябва да го променяш постояно ако нещо се измени.

Или просто не мога да му видя ползата (не съм го разбрал).
Ако може едно разяснение на тази тема.
 
eddyy93 каза:
Някои също ползват DiC (DI container), но той нещо не ми се вижда много от полза, пък и много замотан става през него кода а и трябва да го променяш постояно ако нещо се измени.

Или просто не мога да му видя ползата (не съм го разбрал).
Ако може едно разяснение на тази тема.

Контейнера ти създава обектите и той се грижи да им подава правилните неща. Полезно е ако ще създаваш на много места тия обекти с еднакви параметри. Просто ще са на 1 място - в контейнера - и ако трябва да променяш ще пипнеш само на 1 място
 
Ето един DiC чрез interface arrayaccess:
http://pimple.sensiolabs.org/

А ето и какъв е интерфейса:
http://php.net/manual/en/class.arrayaccess.php

Да доста е гъвкаво, записваме обектите във един масив и се разполагаме с него както искаме.

Чрез такъв масив не е ли по - добре от примера горе?
Да вземем примера горе, ако искаме създадения обект Lock да го вкараме и в друг основен клас, но ни се налага от друг файл (тоест не може да използваме вече създадената инстанция), то тогава този обект ще се създаде 2 пъти .

или

трябва да използваме нещо като централен файл в който да зареждаме всички възможно инстанции + един AutoLoader и в този файл да си разпределяме, кой обект какво да ползва и т.н. Тоест целия този файл ще играе ролята като масива (който предлагат от сайта горе).

Също така този масив горе ми се вижда леко пренатоварен, ако трябва примерно да му сложим записи от повечко класове. Защо да викаме целия масив само заради един обект, примерно. Горе със централния файл всичко на куп и си ги зареждам кое - където трябва.

Вече много се обърках май ...

Кое да ползвам?

Първият пример (който дадох във първото мнение):
Ако извикваме обекта house два пъти някъде, то той трябва 2 пъти да извика Lock и Door примерно за да върне някакъв резултат.

Ако използваме масива: Тогава ние ще записваме Door и Lock във масива, но и още 15 обекта примерно и когато house поиска Door и Lock, тогава ще трябва да зареди целият масив от 17 обекта, за да вземе само два.

Третият пример: Централният файл, ще зарежда всички възможни обекти и според разни проверки ще препраща необходимата информация където трябва, близък със примера за масива.

Правилно ли ги интерпретирам нещата?


ЕДИТ:

Този начин от вариант три, можем да го направим като един клас, който през конструктора, magic method (__set), или setters да предаваме обектите и според това какъв е обекта, различните методи да зарежда. Ще е на базата на синглетон, тоест ще създадем обекта и при повторно поискване на този обект (примерно house), той ще ни върне вече първоначално създадения обект. Ще го ползваме и като Factory, тоест ще става ето така:

PHP:
$Main = new Main();
$Main -> build('house');

Така ако House не е инициализиран във главния $Main, тогава го създай и го върни, след това го ползвай, ако е инициализиран само го върни и го ползвай.

А всичките обекти, който са като House, ще създада един масив, който с foreach да го обхожда във $Main и на базата на него да се зареждат нещата.

Какво мислите, как ще е (как да го кажа) може би най - оптимизирания вариант, а също и така в който не се губи силата на DI.


Ето какво открих:

http://www.potstuck.com/2010/09/09/php-dependency-a-php-dependency-injection-framework/
 
Добре, мисля че си реших г/д проблема.

Ще се ползват и 2 та вида. Като DiC ще го ползва за основните класове и класовете, който му вкарват обектите за да работи.

Същите тези под - класове, ако може да ги наречем така, ако те ползват някъде други обекти, за да създадат нещо, тогава ще ги ползвам със първият пример (само DI), това го правя с цел, контейнера да не стане гигантски или пък да пиша 4 - 5 контейнера. За сега ще тествам така, а пък ще видим по нататък.
 

Back
Горе