За последние 24 часа нас посетили 22083 программиста и 1129 роботов. Сейчас ищут 833 программиста ...

self или satic из трейта?

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

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

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

    С нами с:
    19 июн 2017
    Сообщения:
    615
    Симпатии:
    24
    PHP:
    1. <?php
    2.  
    3.  
    4. namespace core;
    5.  
    6.  
    7. trait Singleton
    8. {
    9.     private static $instance;
    10.  
    11.     private static function getInstance()
    12.     {
    13.         return self::$instance = self::$instance ?? new self();
    14.     }
    15. }
    подключаем трейт

    PHP:
    1. <?php
    2.  
    3.  
    4. namespace core;
    5.  
    6.  
    7. use PDO;
    8.  
    9. class Database
    10. {
    11.     use Singleton;
    12.     public static $count_instances = 0;
    13.     private static $pdo;
    14.  
    15.     private function __construct()
    16.     {
    17.         self::$count_instances++;
    18.         $database = Config::file('database');
    19.         self::$pdo = new PDO($database['dsn'], $database['username'], $database['passwd'], $database['options']);
    20.     }
    21.  
    22.     public static function getServerVersion()
    23.     {
    24.         return self::getInstance()::$pdo->getAttribute(PDO::ATTR_SERVER_VERSION);
    25.     }
    26. }
    Что имеем?

    Всё прекрасно работает, НО PhpStorm в методе getServerVersion() подсвечивает - свойство ::$pdo не найдено в Singleton :)

    Шторм перестаёт светить это свойство, если я методу getInstance() пропишу доки /** @return static */ либо пропишу new static() вместо new self().

    Ну так а как реально должно выглядеть создание инстанса в трейте: self или static И ПОЧЕМУ?

    И если static, то особенно ПОЧЕМУ? Разве трейт не часть класса, в котором создаётся экземпляр, разве он не self?

    Повторяю: всё работает, интересует поведение шторма: почему просит вернуть ему из трейта static методом или доками - это ошибка разработчиков IDE или есть основания?
     
    #1 Вероломство, 7 дек 2020
    Последнее редактирование: 7 дек 2020
  2. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.752
    Симпатии:
    1.322
    Адрес:
    Лень
    Попробуй, ругается ?
    PHP:
    1. <?php
    2.  
    3. trait Singl
    4. {
    5.     private static DB $inst;
    6.    
    7.     public static function getInst(): DB // : return type
    8.     {
    9.         return self :: $inst = self :: $inst ?? new self;
    10.     }
    11. }
    12.  
    13. class DB
    14. {
    15.     private static int $p = 0;
    16.    
    17.     use Singl;
    18.    
    19.     private function __construct()
    20.     {
    21.         self :: $p++;
    22.     }
    23.    
    24.     private static function getP()
    25.     {
    26.         return self :: $p;
    27.     }
    28.    
    29.     public static function run()
    30.     {
    31.         return self :: getInst() :: getP();
    32.     }
    33. }
    34.  
    35. var_dump ( DB :: run() );
     
  3. mkramer

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

    С нами с:
    20 июн 2012
    Сообщения:
    8.555
    Симпатии:
    1.754
    @MouseZver Фишка трейта пропадает. У ТС видимо много синглтонов, он не хочет писать каждый раз одно и то же.

    @Вероломство Ну на то, что там рисует шторм, можно иногда и забить. Я всё, что он мне рисует, читаю, но часть его замечаний посылаю нафиг.

    И сейчас идёт тенденция к тому, чтобы вместо синглтонов использовать DI-контейнеры, и получать зависимости из них. Синглтон уже считается устаревшим паттерном. Он, в принципе, обладает всеми недостатками обычной глобальной переменной.
     
    MouseZver и Вероломство нравится это.
  4. Вероломство

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

    С нами с:
    19 июн 2017
    Сообщения:
    615
    Симпатии:
    24
    всё верно, трейт нужен многократно (может быть), контейнер не нужен: нет смысла таскать с собой массив объектов из объекта в объект, я могу и Реестром это сделать, проект простой, достаточно Одиночки, но я с трейтами если честно первый раз связался, нужно суть понять - это наследование или добавление кода в существующий класс?

    А то в инстансе и при static и при self у меня экземпляр класса, куда подключен трейт, следовательно это не наследование, но IDE подсвечивает при new self() свойства класса, как несуществующие в трейте (нельзя же создать экземпляр трейта, откуда сообщение, что в нём нет свойства?) :), то есть IDE просит создавать экземпляр, как бы наследника в родителе через static, почему? :)

    Ошибка IDE?

    Получается так, ОК, порешали.
     
  5. mkramer

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

    С нами с:
    20 июн 2012
    Сообщения:
    8.555
    Симпатии:
    1.754
    Автоматизированная копипаста :) Сделана в принципе для имитации множественного наследования, но по сути, просто код трейта вставляется в класс, как если бы ты его туда закопипастил. Есть конечно некоторые трюки по переименованию методов, чтоб было не совсем уж примитивно, но когда ты просто пишешь use без других конструкций, получается копипаста.

    Так не надо ничего таскать, нормальные реализации di поддерживают автовайринг. Но дело твоё. Так, для справки оставлю, может кто ещё зайдёт: https://php-di.org/
    --- Добавлено ---
    Ну с ПХП приходится практически искусственный интеллект на стороне IDE разводить, может где-то и не верно понять Но код исполняет не она, поэтому можно иногда и плюнуть на то, что там она нарисовала
     
    Вероломство нравится это.
  6. Вероломство

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

    С нами с:
    19 июн 2017
    Сообщения:
    615
    Симпатии:
    24
    php-di видел, навскидку сделано неплохо, но так и не понял, как коллбэк-вызов спасает от того, что в контейнере массив объектов мы таскаем потом за собой, ну вызвали на момент надобности и потом не надо, может я не до конца вник? Так я могу и просто контейнер создать с методом get, который будет проверять по ключу есть ли объект, если нет, то создавать его методом set (вызванном внутри метода get) :) и возвращать, но он же в контейнере останется

    не ну я чёт в DI не понимаю, если не нужен объект, где он после того, когда его вызвали, где он нужен? В контейнере, в массиве, который пронизывает весь скрипт? А смысл? Я и так могу нужный мне экземпляр создать там где надо как минимум одним способом - new :)
     
  7. mkramer

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

    С нами с:
    20 июн 2012
    Сообщения:
    8.555
    Симпатии:
    1.754
    Прочитай про инверсию зависимостей, один из принципов SOLID.

    Особенно в случае PHP это вообще не важно, через несколько миллисекунд мучения этого объекта закончатся.
    --- Добавлено ---
    Метод гет - это не самое крутое в контейнере. Самое крутое https://php-di.org/doc/autowiring.html
     
    Вероломство нравится это.
  8. Вероломство

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

    С нами с:
    19 июн 2017
    Сообщения:
    615
    Симпатии:
    24
    да знаю я просто мнительный такой не хочу лишний кб памяти коду дать :)
     
  9. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.752
    Симпатии:
    1.322
    Адрес:
    Лень
  10. Вероломство

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

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

    или в чём фишка?
     
  11. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.752
    Симпатии:
    1.322
    Адрес:
    Лень
    в смысле каждый раз перезаписывать ?

    ща погодь..
     
  12. Вероломство

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

    С нами с:
    19 июн 2017
    Сообщения:
    615
    Симпатии:
    24
    ну ты там убеждаешься что является инстансом и поэтому опять переписываешь что ли...

    так это я уже описывал проще: метод set() в методе get() при отсутствии и возврат либо возврат существующего, зачем перезаписывать если есть, просто вернуть, не?
    --- Добавлено ---
    и там проверка странная, если не null, то вернём null
    PHP:
    1. if ( ! isset ( $this -> container[$name] ) )
    2.         {
    3.             return null;
    4.         }
     
  13. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.752
    Симпатии:
    1.322
    Адрес:
    Лень
    PHP:
    1. <?php
    2.  
    3. use Nouvu\{
    4.     Container,
    5.     Config
    6. };
    7.  
    8.  
    9. $container = new Container;
    10.  
    11. // Загружаем контейнер классами без их иницилизации
    12.  
    13. # - Database class
    14. $container -> set( 'database', function ( Container $cont ): \PDO
    15. {
    16.     $database = $cont -> get( 'config' ) -> get( 'Database.connect' );
    17.    
    18.     return new \PDO( $database['dsn'], $database['username'], $database['passwd'], $database['options'] );
    19. } );
    20.  
    21. # - Config class
    22. $container -> set( 'config', fn( Container $cont ) => new Config );
    23.  
    24. // - end
    25.  
    26.  
    27.  
    28. // что - то для примера
    29.  
    30. class test
    31. {
    32.     protected Container $container;
    33.    
    34.     public function __construct( Container $cont )
    35.     {
    36.         $this -> container = $cont
    37.     }
    38.    
    39.     public function getHrenZnaet(  )
    40.     {
    41.         $sql = 'SELECT ...'
    42.        
    43.         return $this -> container -> get( 'database' ) -> query( $sql );
    44.     }
    45. }
    46.  
    47.  
    48.  
    49.  
    50. $test = new test( $container );
    51.  
    52. print_r ( $test -> fetchAll() );
     
  14. Вероломство

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

    С нами с:
    19 июн 2017
    Сообщения:
    615
    Симпатии:
    24
    и что это за ПЕРЕХИТРИМ ВСЕХ: загружаем классы без инициализации? Загружаем в таком случае массив неймспейсов и по мере обращения делаем тупо NEW :) тем же самым геттером
     
  15. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.752
    Симпатии:
    1.322
    Адрес:
    Лень
    чего ?
    каким боком там null если тебе ошибку выкинет при не существовании класса с определенным ключём ?
    PHP:
    1. $a = [ 1,2 ];
    2.  
    3. if ( ! isset ( $a['database'] ) )
    4. {
    5.    echo 666;
    6. }
    --- Добавлено ---
    один раз загружается а дальше берет экземпляр УЖЕ загруженного класса :)

    Если тип в контейнере "функция", то обращаемся к ней как к функции, а значение перезаписываем.
    Дальше при обращении контейнер не определит значение как функцию, так как будет там уже класс $this -> container[$name] instanceof \Closure ===== false
    PHP:
    1. if ( $this -> container[$name] instanceof \Closure )
    2.         {
    3.             $this -> container[$name] = $this -> container[$name]( $this );
    4.         }
     
  16. Вероломство

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

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

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.752
    Симпатии:
    1.322
    Адрес:
    Лень
    где, когда и во сколько ? o_O
     
  18. Вероломство

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

    С нами с:
    19 июн 2017
    Сообщения:
    615
    Симпатии:
    24
    PHP:
    1. $a = null;
    2. if (!isset($a)) {
    3.     echo 'А зачем ты проверил меня на NULL и вернул NULL?';
    4.     return null;
    5. }
    --- Добавлено ---
    @MouseZver
    слово перезапись я вижу или как? :)
     
  19. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.752
    Симпатии:
    1.322
    Адрес:
    Лень
    откуда у тебя $a без типа массива ?
    Как проверяешь массивы на сущ ключи ?
    --- Добавлено ---
    PHP:
    1. $this -> container[$name] = $this -> container[$name]( $this );
    Ты прикалываешься или реально не видишь ?
     
  20. Вероломство

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

    С нами с:
    19 июн 2017
    Сообщения:
    615
    Симпатии:
    24
    @MouseZver, смотри у меня в контейнере экземпляр user (User, то есть МЕНЯ), как мне посмотреть другого User по ключу контейнера user?

    Это одна и та же сущность только айдишник другой будет, мне нужно видеть свои некоторые данные в шаблоне и данные другого пользуна используя одну и ту же сущность...

    в контейнере по ключу user - Я
     
    #20 Вероломство, 8 дек 2020
    Последнее редактирование: 8 дек 2020
  21. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.752
    Симпатии:
    1.322
    Адрес:
    Лень
    самкласс = контейнер -> гет( имя )
    --- Добавлено ---
    заюзай практику, ты на теореме повяз.
     
  22. Вероломство

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

    С нами с:
    19 июн 2017
    Сообщения:
    615
    Симпатии:
    24
    контейнер->(user) - Я

    хочу видеть другого

    контейнер->(user) - опять Я :)
     
  23. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.752
    Симпатии:
    1.322
    Адрес:
    Лень
    контейнер->(neuser) - не ты
     
  24. Вероломство

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

    С нами с:
    19 июн 2017
    Сообщения:
    615
    Симпатии:
    24
    вот и разрушился контейнер, нельзя передать одну сущность из контейнера для нескольких :)

    и будем таскать за собой всю эту дичь передавая из класса в класс вместо того чтобы вызвать по месту отработать, записать данные в БД и никакой другой класс об этом даже не будет знать: если я смотрю профиль второго юзера, то зачем мне контейнер с экземплярАМИ третьего, четвёртого, пятого и т.д., которыЕ создавались и помещались в контейнер по мере захода на них, правильно?

    А вот если мы храним в контейнере неймспейс, то по месту на его основании мы создаём и присваиваем экземпляр, НО НЕ берём уже готовый.

    Так зачем мне массив даже неймспейсов, я сделаю NEW в любом месте.
     
    #24 Вероломство, 8 дек 2020
    Последнее редактирование: 8 дек 2020
  25. mkramer

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

    С нами с:
    20 июн 2012
    Сообщения:
    8.555
    Симпатии:
    1.754
    То, что лежит в контейнере - большей частью аналоги синглтонов, т.е. они в нескольких экземплярах не нужны в системе. То есть положить туда текущего юзера нормально, а если нужен другой юзер - ок, запрашиваешь другого юзера из репозитория или ещё откуда-нибудь, как у тебя заведено. Чем лучше синглтонов - тем что не создаётся прямая зависимость, можно вешать разные реализации, можно вешать по интерфейсу, и менять реализацию, в зависимости от текущей задачи, отладки, тестирования и т.п.
     
    Вероломство нравится это.