За последние 24 часа нас посетили 22395 программистов и 1058 роботов. Сейчас ищут 640 программистов ...

Обломы с автовайрингом

Тема в разделе "PHP для новичков", создана пользователем Вероломство, 3 авг 2022.

  1. Вероломство

    Вероломство Активный пользователь

    С нами с:
    19 июн 2017
    Сообщения:
    615
    Симпатии:
    24
    Ну вот смотрите, загнал я приложение в контейнер:
    PHP:
    1. $container = new Container();
    2.  
    3. $application = $container->get(Application::class);
    4.  
    5. // класс Application
    6. class Application
    7. {
    8.     public function __construct(Container $container)
    9.     {
    10.         var_dump($container); // нет ТАМ никакого Application, голый контейнер :)
    11.     }
    12. }
    Хорошо, чтобы получить доступ к содержимому контейнера, то идём другим путём:

    PHP:
    1. $container = new Container();
    2.  
    3. $container->set(Application::class, function(Container $container) {
    4.     return new Application($container); // как я понимаю на этом месте автовайринг закончился
    5. });
    6.  
    7. $application = $container->get(Application::class);
    8.  
    9. // класс Application
    10. class Application
    11. {
    12.     public function __construct(Container $container /* тут если сделать ещё одну инъекцию, то автовайринг не работает */)
    13.     {
    14.         var_dump($container); // ТАМ есть Application :)
    15.     }
    16. }
    Вопрос: как мне теперь в классе Application использовать автовайринг (выше в комментарии класса)?

    Как я понимаю автовайринг закончился на моменте, когда я мануалом передал в него хоть один параметр, после этого я могу только мануалом туда добавлять?

    То есть суть такая: как мне в других классах получать содержимое контейнера?

    Я если добавляю класс в контейнер и передаю контейнер или содержимое по ключу из контейнера в его конструктор, то у меня прекращает работать автовайринг в конструкторе класса, где вручную был добавлен параметр.
     
    #1 Вероломство, 3 авг 2022
    Последнее редактирование: 3 авг 2022
  2. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.751
    Симпатии:
    1.322
    Адрес:
    Лень
    Для чего у тебя Application ?
    --- Добавлено ---
    Для чего у тебя Application ?
    --- Добавлено ---
    Для чего у тебя Application ?
     
  3. Вероломство

    Вероломство Активный пользователь

    С нами с:
    19 июн 2017
    Сообщения:
    615
    Симпатии:
    24
    там много чего и это всё в конструкторе создаётся
     
  4. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.751
    Симпатии:
    1.322
    Адрес:
    Лень
    ты уже пол года с Application возишься.
    --- Добавлено ---
    Так для чего у тебя Application ?

    Придет время, ты сможешь ответить на этот вопрос и все проблемы исчезнут
     
  5. Вероломство

    Вероломство Активный пользователь

    С нами с:
    19 июн 2017
    Сообщения:
    615
    Симпатии:
    24
    придёт время и я получу ответ на https://php.ru/forum/threads/mozhno-li-vnedrjat-sam-kontejner-pri-avtovajringe.96055/#post-649722
    --- Добавлено ---
    @MouseZver пытаюсь понять: нафиг мне нужен контейнер )))
     
  6. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.751
    Симпатии:
    1.322
    Адрес:
    Лень
    Пишем об А, думает об Б, лезет в С o_O
    --- Добавлено ---
    причем тут контейнер ?
     
  7. Вероломство

    Вероломство Активный пользователь

    С нами с:
    19 июн 2017
    Сообщения:
    615
    Симпатии:
    24
    смотри:

    PHP:
    1. class A
    2. {
    3.     public function __construct($a, B $b, C $c) {}
    4. }
    $a - это какое-то значение из контейнера, хорошо

    PHP:
    1. $container->set(A::class, function() use ($container) {
    2.     return new A($container->get('a'));
    3. });
    4.  
    5. $container->get(A::class);
    как видим автовайринг B $b, C $c в конструкторе класса A работает ))) то есть нужно всё ручками добавлять, если добавил хотя бы один параметр и поместил в контейнер

    А если у меня сотня инъекций с разными типами?
    --- Добавлено ---
    как время есть так и вожусь )))
     
  8. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.751
    Симпатии:
    1.322
    Адрес:
    Лень
    уже в D полез когда спрашивал об Б, а там спрашивал изначально об А, но увы перейдешь в E
     
  9. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.554
    Симпатии:
    1.754
    Откуда же мы знаем, как ты его реализовал? Этот автовайринг
    --- Добавлено ---
    Я же так понимаю, полный самопис?
     
  10. Вероломство

    Вероломство Активный пользователь

    С нами с:
    19 июн 2017
    Сообщения:
    615
    Симпатии:
    24
    как видим автовайринг B $b, C $c в конструкторе класса A НЕ работает
     
  11. Вероломство

    Вероломство Активный пользователь

    С нами с:
    19 июн 2017
    Сообщения:
    615
    Симпатии:
    24
    PHP:
    1. <?php
    2.  
    3.  
    4. namespace core;
    5.  
    6.  
    7. use Closure;
    8. use Exception;
    9. use ReflectionClass;
    10.  
    11. class Container
    12. {
    13.     private $dependencies;
    14.     private $results = [];
    15.  
    16.     public function __construct($dependencies = [])
    17.     {
    18.         $this->dependencies = $dependencies;
    19.     }
    20.  
    21.     public function set($key, $value)
    22.     {
    23.         if (array_key_exists($key, $this->results)) {
    24.             unset($this->results[$key]);
    25.         }
    26.  
    27.         $this->dependencies[$key] = $value;
    28.  
    29.         return $this;
    30.     }
    31.  
    32.     public function has($key)
    33.     {
    34.         return array_key_exists($key, $this->dependencies) || class_exists($key);
    35.     }
    36.  
    37.     public function get($key)
    38.     {
    39.         if (array_key_exists($key, $this->results)) {
    40.             return $this->results[$key];
    41.         }
    42.  
    43.         if (!array_key_exists($key, $this->dependencies)) {
    44.  
    45.             if (class_exists($key)) {
    46.                 $reflectionClass = new ReflectionClass($key);
    47.                 $args = [];
    48.  
    49.                 if ($constructor = $reflectionClass->getConstructor()) {
    50.  
    51.                     foreach ($constructor->getParameters() as $parameter) {
    52.  
    53.                         if ($class = $parameter->getClass()) {
    54.                             $args[] = $this->get($class->name);
    55.                         } elseif ($parameter->isArray()) {
    56.                             $args[] = [];
    57.                         } elseif (!$parameter->isDefaultValueAvailable()) {
    58.                             throw new Exception("Не указано значение по умолчанию параметра: $parameter->name");
    59.                         } else {
    60.                             $args[] = $parameter->getDefaultValue();
    61.                         }
    62.  
    63.                         /* PHP 8
    64.                        
    65.                         if (!$parameter->hasType()) {
    66.                             throw new Exception("Не указан тип параметра: $parameter->name");
    67.                         }
    68.  
    69.                         if ($parameter->getType()->isBuiltin()) {
    70.  
    71.                             if (!$parameter->isDefaultValueAvailable()) {
    72.                                 throw new Exception("Не указано значение по умолчанию параметра: $parameter->name");
    73.                             }
    74.  
    75.                             $args[] = $parameter->getDefaultValue();
    76.                         } else {
    77.                             $args[] = $this->get($parameter->getType()->getName());
    78.                         } */
    79.                     }
    80.                 }
    81.  
    82.                 return $this->results[$key] = $reflectionClass->newInstanceArgs($args);
    83.             }
    84.  
    85.             throw new Exception("Не найдена зависимость: $key");
    86.         }
    87.  
    88.         $dependency = $this->dependencies[$key];
    89.  
    90.         if ($dependency instanceof Closure) {
    91.             $this->results[$key] = $dependency($this);
    92.         } else {
    93.             $this->results[$key] = $dependency;
    94.         }
    95.  
    96.         return $this->results[$key];
    97.     }
    98. }
     
  12. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.554
    Симпатии:
    1.754
    О, блин... А с чего оператор new полезет в твой контейнер :))) Он знать о нём не знает
     
  13. Вероломство

    Вероломство Активный пользователь

    С нами с:
    19 июн 2017
    Сообщения:
    615
    Симпатии:
    24
    это ленивая подгрузка анонимкой, анонимка знает о контейнере, там в контейнере в методе get в экземпляр Closure предусмотрена передача контейнера и в анонимку он передаётся явно, если даже явно не передавать, то передать можно в анонимку через use

    Суть не в этом, а в том, что если я заполню хоть один параметр при ручном добавлении в контейнер, то у меня потом в конструкторе не будет работать автовайринг, там будет только то, что я передал ручным заполнением