Singleton DI

teroristd

Registered
Продължавам с темата за DI :) . Контейнерът работи нормално, но стои въпросът как да го ъпдейтна за да мога инжектирам сингълтони? Искам да попитам също, лошо ли е ако самия контейнер е сингълтон? И последно ако мислите че изобщо не трябва да използвам сингълтони, то тогава как да процедирам с класове, като например конекцията към базата данни, когато ми трябва една и съща конекция на много различни места?

Код:
namespace application;

class Container {

    private static $_instance = NULL;

    private function __construct() {
        
    }





    /** @return \application\Container */
    public static function getInstance() {

        if (self::$_instance === NULL) {
            self::$_instance = new self();
        }

        return self::$_instance;
    }





    public function make($class) {

        $reflector = new \ReflectionClass($class);

        if (!$reflector -> isInstantiable()) {

            throw new \Exception('This Class ' . $class . ' Is Not Instantiable In: ' . __METHOD__, 500);
        }

        $constructor = $reflector -> getConstructor();

        if (is_null($constructor)) {

            return new $class;
        }

        $parameters = $constructor -> getParameters();

        $dependencies = $this -> getDependencies($parameters);

        return $reflector -> newInstanceArgs($dependencies);
    }





    public function getDependencies($parameters) {

        $dependencies = array();

        foreach ($parameters as $parameter) {

            $dependency = $parameter -> getClass();

            if (is_null($dependency)) {

                $dependencies[] = $this -> makeNoClass($parameter);
            }
            else {

                $dependencies[] = $this -> make($dependency -> getName());
            }
        }

        return $dependencies;
    }





    public function makeNoClass(ReflectionParameter $parameter) {

        if ($parameter -> isDefaultValueAvailable()) {

            return $parameter -> getDefaultValue();
        }

        throw new \Exception('This Parameter ' . $parameter . ' Is Unknown In: ' . __METHOD__, 500);
    }





}
 
Добре, и все пак какво се прави като ми трябва една и съща инстанция на много места?
 
Не разбирам как ще стане това? Евентуално трябва да имам някаква глобална променлива, което е тъпо и трябва да правя конекцията в началото на приложението, а може да не ми е необходима. Изобщо може да стане голяма каша, а и не е само конекцията има и други класове, които се нуждаят от същата функционалност. Четох за сингълтона мнения че бил антипатерн, но се оказа че не е точно така. Има хора които са на мнение че трябва да се ползва когато е необходим, също така във всички големи фреймуорци се поддържа.
 
Да продължа мисълта си от предния пост. Та сингълтона, да се изразя така, не го харесват, защото криел зависимостите в себе си и бил труден за тестване. За тестването не мога да кажа нищо, абсолютно бос съм по тая тема, не знам какво точно им пречи, но това за зависимостите има начин да се избегне. Идеята ми е такава, първо когато правя сингълтон няма да слагам никакви зависимости в него, след това го обгръщам с друг клас, който е с публичен конструктор и ще може да се инжектира. Един вид сънгълтона държи просто конекцията например, а другия клас държи инстанция на сингълтона. Така няма да се крият никакви зависимости и ще съм сигурен че имам точно една конекция.

Знам че фреймуорците по някакъв начин са направили да може да се инжектира сингълтон, интересно ми е как?
 
Идея за размисъл: в Spring например по подразбиране всички beans са сингълтони - т.е. когато инжектираш някъде, ще е 1 и съща инстанция. Има опция всеки път нов да създава. Не съм изучавал вътрешностите на DI, но не е ли въпрос на една допълнителна опция и един if?
 
djman каза:
Идея за размисъл: в Spring например по подразбиране всички beans са сингълтони - т.е. когато инжектираш някъде, ще е 1 и съща инстанция. Има опция всеки път нов да създава. Не съм изучавал вътрешностите на DI, но не е ли въпрос на една допълнителна опция и един if?

Не съм запознат с Spring, но не е само до един if, защото при сингълтона конструктора е private и рефлекшън класа не може да достъпи никакви параметри. Но не е и само това става объркване и със статичните свойства и функции.
 
Изглежда, че бъркаш DI, DI Containers и injection чрез reflection. Решението е много лесно, но няма да ти го казвам, само ще подскажа, че djman е прав. Върни се на предната тема и прочети 2-3 линка.
 
lam3r4370 каза:
Изглежда, че бъркаш DI, DI Containers и injection чрез reflection. Решението е много лесно, но няма да ти го казвам, само ще подскажа, че djman е прав. Върни се на предната тема и прочети 2-3 линка.

Колега кажи какво имаш предвид. Прегледах всички линкове, но не мога да разбера какво трябва да направя.
 
Виж, имаш един контейнер, който се грижи за създаването на инстанции и който пази споделените aka singleton такива. Ето прост пример

Код:
class Container {
  private static $shared = [];
  public static function singleton($class) {
    if(!$shared[$class]) {
      $shared[$class] = new $class;
    }
  }
  public static function resolve($class) {
    if($shared[$class]) return $shared[$class];
    return new $class;
  }
}

И вече ако искаш нещо да е singleton първо го слагаш в контейнера
Код:
Container::singleton($dbclass);

И като искаш да вземеш дадена инстанция, каквато и да е

Код:
Container::resolve($class);
 

Back
Горе