Drukowana wersja tematu

Kliknij tu, aby zobaczyć temat w orginalnym formacie

Forum PHP.pl _ Oceny _ [PHP][class] Prosty container

Napisany przez: untorched 5.10.2014, 00:16:09

Witam.
Chciałem przedstawić klasę prostego kontenera.
Wzorowałem się na kontenerze z laravela, lecz nie "kopiowałem", a pisałem samodzielnie, co na pewno widać smile.gif
Chciałbym prosić o ocenę kodu, w miarę możliwości tego jak będzie wydajny oraz wytknięcie błędów.

Z góry dziękuję za waszą pomoc smile.gif

  1. class Container implements ArrayAccess {
  2.  
  3. protected $bindings = http://www.php.net/array();
  4.  
  5. protected $instances = http://www.php.net/array();
  6.  
  7. private $maxdepth = 10;
  8.  
  9. // ================================================== //
  10.  
  11. public function make($key, $params = http://www.php.net/array())
  12. {
  13. if($bind = $this->getBinding($key))
  14. {
  15. if(http://www.php.net/isset($bind['closure']))
  16. {
  17. if(http://www.php.net/isset($bind['singleton']) and $bind['singleton'] === true)
  18. {
  19. $bind['instance'] = $bind['closure']();
  20. $this->instances[$key] = $bind['instance'];
  21.  
  22. http://www.php.net/unset($this->bindings[$key]['closure'], $this->bindings[$key]['singleton']);
  23. }
  24. else
  25. {
  26. $bind['instance'] = $bind['closure']();
  27. }
  28. }
  29.  
  30. return $bind['instance'];
  31. }
  32. else
  33. {
  34. $ret = $this->makeClassWithParams($key, (http://www.php.net/array)$params);
  35.  
  36. if($ret != false)
  37. {
  38. $this->bind($key, $ret);
  39. }
  40.  
  41. return $ret;
  42. }
  43. }
  44.  
  45. public function bind($key, $value)
  46. {
  47. return $this->makeBinding($key, $value, false);
  48. }
  49.  
  50. public function singleton($key, $value)
  51. {
  52. return $this->makeBinding($key, $value, true);
  53. }
  54.  
  55. // ================================================== //
  56.  
  57. protected function makeClassWithParams($name, http://www.php.net/array $params, $depth = 1)
  58. {
  59. if($depth >= $this->maxdepth)
  60. {
  61. throw new OutOfBoundsException('Maximum depth of makeClassWithParams is '.$this->maxdepth);
  62. return false;
  63. }
  64.  
  65. if(class_exists($name))
  66. {
  67. $class = new ReflectionClass($name);
  68.  
  69. $constructor = $class->getConstructor()->getParameters();
  70.  
  71.  
  72. if(!http://www.php.net/empty($constructor) and http://www.php.net/empty($params))
  73. {
  74. $constructor = $class->getConstructor()->getParameters();
  75.  
  76. foreach($constructor as $classparam)
  77. {
  78. $classparam = $classparam->getClass();
  79.  
  80. if(http://www.php.net/is_null($classparam))
  81. {
  82. $params[] = null;
  83. }
  84. else
  85. {
  86. $params[] = $this->makeClassWithParams($classparam->name, http://www.php.net/array(), $depth+1);
  87. }
  88. }
  89.  
  90. $class = $class->newInstanceArgs($params);
  91. }
  92. else
  93. {
  94. $class = $class->newInstanceArgs($params);
  95. }
  96.  
  97. return $class;
  98. }
  99. else
  100. {
  101. http://www.php.net/echo $name;
  102. return false;
  103. }
  104. }
  105.  
  106. protected function makeBinding($key, $value, $singleton)
  107. {
  108. $this->clearBinding($key);
  109.  
  110. $bind = http://www.php.net/array();
  111.  
  112. $bind['instance'] = $key;
  113.  
  114. if($value instanceof Closure)
  115. {
  116. $bind['closure'] = $value;
  117. $bind['singleton'] = (bool)$singleton;
  118. }
  119. else
  120. {
  121. $bind['instance'] = $value;
  122. }
  123.  
  124. if(http://www.php.net/isset($bind['instance']))
  125. {
  126. $this->instances[$key] = $bind['instance'];
  127. }
  128. else
  129. {
  130. $this->instances[$key] = null;
  131. }
  132.  
  133. $bind['instance'] = $key;
  134.  
  135. $this->bindings[$key] = $bind;
  136. }
  137.  
  138. protected function getBinding($key)
  139. {
  140. if(http://www.php.net/isset($this->bindings[$key]))
  141. {
  142. $bind = $this->bindings[$key];
  143.  
  144. if(! http://www.php.net/is_null($this->instances[$key]))
  145. {
  146. $bind['instance'] = $this->instances[$key];
  147. }
  148.  
  149. return $bind;
  150. }
  151.  
  152. return false;
  153. }
  154.  
  155. protected function clearBinding($key)
  156. {
  157. http://www.php.net/unset($this->bindings[$key], $this->instances[$key]);
  158. }
  159.  
  160. // ================================================== //
  161.  
  162. public function offsetGet($key)
  163. {
  164. return $this->make($key);
  165. }
  166.  
  167. public function offsetSet($key, $value)
  168. {
  169. $function = function() use ($value) {
  170. return $value;
  171. };
  172.  
  173. $this->bind($key, $function);
  174. }
  175.  
  176. public function offsetExists($key)
  177. {
  178. return http://www.php.net/isset($this->bindings['key']);
  179. }
  180.  
  181. public function offsetUnset($key)
  182. {
  183. $this->clearBinding($key);
  184. }
  185.  
  186. public function __set($key, $value)
  187. {
  188. $this[$key] = $value;
  189. }
  190.  
  191. public function __get($key)
  192. {
  193. return $this[$key];
  194. }
  195.  
  196. }

Napisany przez: !*! 7.10.2014, 08:33:12

Byłoby prościej jakbyś napisał o co w tym chodzi, jak tego użyć i stworzył dokumentacje ;)

Napisany przez: Daimos 7.10.2014, 21:26:06

Kurcze też Wam zahashowało komentarze na // ================================================== //
?
wink.gif

Napisany przez: untorched 8.10.2014, 21:55:58

Nie ma opcji edytuj więc muszę dorzucić to tutaj.

Przepraszam za brak komentarzy i opisu działania, nadrobiłem, są komentarze(błędy stylistyczne, błędy składni językowej lub inne dziwne rzeczy mogą się tam znaleźć niestety). Poniżej zamieszczam kod oraz użycie

http://pastebin.com/2H0FsKsB

  1. // Tworzenie instancji kontrolera, można również rozszerzyć jakąś klasę
  2. $container = new Container();
  3.  
  4. // Dodanie tekstu do kontenera
  5. $container->bind('tekst', 'Dowolna zawartość do przechowania');
  6.  
  7. // Dodawanie stworzonej instancji do kontenera
  8. $container->bind('instancja', $container);
  9.  
  10. // Dodanie funkcji anonimowej do kontenera
  11. $container->bind('funkcja_anonimowa', function() {
  12. return http://www.php.net/rand();
  13. });
  14.  
  15. // Dodanie funkcji anonimowej jako singleton do kontenera
  16. $container->bind('funkcja_anonimowa_singleton', function() {
  17. return http://www.php.net/rand();
  18. }, true);
  19.  
  20. // Tworzenie klasy przy użyciu kontenera wraz z wymaganymi parametrami konstruktora
  21. class Test1 {}
  22. class Test2 {}
  23. class Test3 {}
  24.  
  25. class Example {
  26. public function __construct(Test1 $test1, Test2 $test2, Test3 $test3) {}
  27. }
  28.  
  29. $container->make('Example');
  30.  
  31. // ================================================================= //
  32.  
  33. /**
  34.  * Testowanie przechowywanych rzeczy.
  35.  * Można użyć $container->nazwa_bindu;
  36.  * Można użyć $container->make('nazwa_bindu');
  37.  * Można użyć $container['nazwa_bindu'];
  38.  */
  39.  
  40. http://www.php.net/var_dump($container->tekst);
  41.  
  42. http://www.php.net/var_dump($container->make('instancja'));
  43.  
  44. http://www.php.net/var_dump($container['funkcja_anonimowa']);
  45.  
  46. http://www.php.net/var_dump($container['funkcja_anonimowa_singleton']);
  47.  
  48. http://www.php.net/var_dump($container['Example']);


Powinno wszystko działać. Aczkolwiek liczę się z tym, że możliwie popełniłem tu kilka błędów.
Proszę o opinie na temat kodu, wygody użycia, braków itd.

Napisany przez: !*! 9.10.2014, 17:36:27

  1. class Demo
  2. {
  3. public $text;
  4.  
  5. public function __construct($text = 'yyyyyyy')
  6. {
  7. $this->text = $text;
  8. }
  9. public function test()
  10. {
  11. return http://www.php.net/rand();
  12. }
  13.  
  14. public function add($t)
  15. {
  16. $this->text = $t;
  17. }
  18. }


  1. $di->make('Demo');


  1. http://www.php.net/var_dump($di->Demo->text);

Zwróci null.

Napisany przez: untorched 9.10.2014, 22:50:16

http://pastebin.com/PUfFshcY

Poprawka.

Faktycznie nie uwzględniłem, że parametr konstruktora może posiadać wartość domyślną.

Dziękuje serdecznie !*! za znalezienie tego buga. Jeśli jest coś jeszcze to chętnie przyjmę to do informacji smile.gif

Napisany przez: !*! 11.10.2014, 13:06:00

Grunt, że działa. Nie wiem jak to się sprawdza w praktyce przy czymś większym. Osobiście mam wrażenie, że trochę przebajerowałeś z makeClassWithParameters i samym ReflectionClass. Choć może to tylko subiektywne odczucie.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)