Внедрение зависимостей в PHP с использованием прыщей - PullRequest
2 голосов
/ 02 апреля 2012

Я новичок в DI, использую прыщ.Использование: php 5.3.5 (wamp), а также пространства имен.Я рефакторинг кода, используя его, но возникли проблемы:

У меня есть мой контейнер, который выходит из Pimple, давайте назовем его PContainer.php:

class ReuseableContainer extends Pimple{

      private function initOutterClass(){
         $this['special_location_class'] = '\SpecialLocation';
         $this['special_location'] = function($c){return new $c['special_location_class']($c['location_details'],$c['location']);};
      }

      private function initGlobalFunctions(){
         $this['getGeneralDataFromArray'] = function($c){
             // returning a function
             return function($arr){
                 foreach ($arr as $key => $value){
                 // do something
                   $new_data = $c['general_data_type'];
                   $new_data->id = $value['id'];
                   $new_data->name = $value['name'];
                 }

         }          

      }

      public function __construct(){
          $this['location_class'] = '\Location';
          $this['location_details_class'] = '\LocationDetails';
          $this['general_data_type_class'] = '\GeneralDataType';
          // define some objects
          $this['location'] = function ($c) {
               return new $c['location_class']();
          };

          $this['location_details'] = function ($c) {
               return new $c['location_details_class']();
          };

          $this['general_data_type'] = function ($c) {
              return new $c['general_data_type_class']();
          };

          $this->initOutterClass();
          $this->initGlobalFunctions();
      }



}
global $container ;
$container = new Pimple();

// embed the SomeContainer container
$container['embed'] = $container->share(function () { return new ReuseableContainer(); });

Ok,Итак, я получил SpecialHelper.php, который содержит:

final class SpecialLocation{
    public $name;
    public $location;
    public $picture;

    public function __construct($location){
        $this->location; // dependent on class: Location
    }
}

final class SpecialUser{
    private $id; 
    private $location;

    public function __construct(\Location $location,$id=''){
        $this->id = $id;
        $this->location = $location; // $container['embed']['location'];
}

, и мы получили наш GeneralHelper.php, который содержит:

final class Location{
    public $lat;
    public $lng;
    public function __construct($lat='',$lng=''){ $this->lat = $lat; $this->lng = $lng;}
}
final class LocationDetails{
    public $id;
    public $addresss;
    public function __construct($id='',$address=''){$this->id = $id; $this->address = $address;}
}
class GeneralDataType{
    public $id;
    public $name;
    public function getName(){ return $this->name;}
    public function getId(){ return $this->id;}
}

, и у нас есть контроллер "Специальный класс", который выглядитчто-то вроде этого:

final class SpecialController{

    public function foor($some_array){
        $this->doSomething($some_array);
    }

    private function doSomething($ret_value){
        // do something
        $arr = array();

        foreach($ret_value as $key => $value){
             $something = $container['embed']['getGeneralDataFromArray']($value);
             $special_location = $container['embed']['special_location'];
             $arr[] = special_location; 
        }
        return $arr;
     }
  }

Наконец, у нас есть наш главный "драйвер", main.php

require('PContainer.php');
....
...
$some_array = array(....);
$special_controller = new SpecialController();
$special_controller->foor($some_array);

Проблемы: 1) Мне пришлось добавить функцию initOutterClass внутри ReuseableContainer, чтобы отделить "Специальные "классы, как я мог бы отделить их лучше?создание нового "специального" 9контейнера или что-то?так как ВСЕ теперь сидит внутри контейнера .. то же самое относится к initGlobalFunctions ()

2) относительно SpecialHelper.php: у меня есть SpecialLocation, одно из его свойств является классом \ Location, я положил егов конструкторе, но если у меня есть 20 свойств объекта, которые являются зависимыми, я должен поместить их все в качестве параметров INPUT для конструктора ??То же самое относится и к классу SpecialUser, у него есть $ location, который, если бы я мог, сделал бы $this->location = $container['embed']['location']; вместо $this->location = $location;, что привело бы к зависимости от DI!: /

3) Мне пришлось создать SpecialHelper.php в другом файле, несмотря на желание поместить его в «контроллер специального класса», просто чтобы не было никаких неизвестных (из-за необходимостипорядок операторов)

4) Самое главное: о контроллере "Специальный класс", как мне решить метод doSomething?я должен создать объект "Special Location" внутри цикла, но я получаю, что $ container не распознан (несмотря на то, что он глобален, вероятно, по области видимости), но более того, он действительно зависим!и это частная функция, я не хочу передавать контейнер в КАЖДЫЙ класс, который я буду использовать с этого момента, это не IoC, верно?

Любая помощь оценивается ... я пытаюсьчтобы понять лучшие практики ..

Спасибо

1 Ответ

1 голос
/ 28 мая 2013

4) Самое главное: IoC правильный.То, что реализация работает некорректно, не отражает принцип самого IoC.

Если вы хотите использовать глобальный контейнер $ внутри функции, то следует использовать ключевое слово global внутри этой функции.Вот как работает PHP.Сделать его статичным - значит решить проблему референций, но не имеет реального значения.

Контейнер IoC разрешает зависимости для вызывающей стороны.Звонящий не должен ничего знать о внутренностях вызываемого абонента - и ему тоже все равно.Итак, должен быть какой-то договор, которым регулируется обмен данными.Если у вас есть такая ситуация, то у вас есть IoC.

3) Эта проблема слишком неопределенная, чтобы ответить на нее, но, с другой стороны, с практической точки зрения она также не актуальна.Это работает?Хорошо, приятно знать: -)

2) Ключом к IoC является использование контрактов.Контейнер IoC предназначен для подключения вызывающего абонента к соответствующему контракту.Контракт разрешается до конкретного абонента.Вызываемая сторона вернет информацию в соответствии с договором.Звонящий понимает ответ.Поэтому вам потребуется, чтобы ввод и вывод в этом процессе не зависели от определенной реализации в определенное время.Поэтому не используйте 20 свойств объекта в качестве входных данных, а вместо этого используйте массив или общий объект.

1) Я понял, что вы смешиваете функциональный поток (поток данных) с техническим потоком (отношения между классами),Контейнер IoC служит цели технического потока, он оптимизирует зависимость в отношениях между классами.Например, если вы хотите подключиться к базе данных, вы можете повторно использовать существующее подключение вместо того, чтобы создавать новые подключения постоянно.Или, если вы хотите использовать специальные функции в течение нескольких моментов в вашем потоке, то вы можете использовать IoC для этого.

...