Доступ к статическим данным

    Начиная с версии 5.3 появилась возможность обращаться к статическим данным классов используя переменную. Благодаря этому мы практически забыли об ошибке «syntax error, unexpected T_PAAMAYIM_NEKUDOTAYIM», которая возникала при попытке использования оператора "::" как-то «не так».

    Но, как мне кажется, об открывшихся возможностях знают не все.

    Создадим интерфейс, класс и объект для экспериментов.

    interface bar{
        const SOME_CONST = 'SOME_CONST';
    
        static public function static_public_function();
        }
    
    class foo implements bar{
    
        static public $static_public_property = 'static_public_propery';
    
        static public function static_public_function(){
            return 'static_public_function';
            }
    
        }
    
    $object = new foo();
    


    Код, который работает как в 5.3 так и ранее. Имея в наличии объект необходимо было выяснить его класс.

    echo foo::SOME_CONST . PHP_EOL; // SOME_CONST
    echo foo::$static_public_property . PHP_EOL; // static_public_property
    echo foo::static_public_function() . PHP_EOL; // static_public_function
    
    echo bar::SOME_CONST . PHP_EOL; // SOME_CONST
    


    Код, который работает начиная с PHP 5.3. Теперь нет необходимости указывать класс.

    echo $object::$static_public_property . PHP_EOL; // static_public_property
    echo $object::SOME_CONST . PHP_EOL; // SOME_CONST
    echo $object::static_public_function() . PHP_EOL; // static_public_function
    


    Константы и статические методы можно было объявлять в интерфейсах начиная с самого начала появления интерфейсов в PHP. Но чтобы работать с ними нужно было указывать имя интерфейса или класса. Сейчас же можно использовать объект для доступа к этим данным. Можно сказать, что начиная с версии 5.3 константы и статические методы стали полноценной частью интерфейса.

    Благодаря этому можно сократить количество употреблений имён классов и интерфейсов. А так же использовать автодополнение IDE имея «на руках» объект.
    Ads
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More

    Comments 9

      +8
      Что-то мне не кажется хорошей идеей использование $object::$static_public_property вместо foo::$static_public_property.

      Как бы обращение к объекту подразумевает под собой динамику (объект — это динамическая сущность класса). Обращение к классу подразумевает статику («не меняется для каждого объекта»). Обращаясь за статическими свойствами к объекту вы вводите в заблуждение читателя. Я понимаю, что разница все равно есть (:: vs ->), но она становится менее заметной.

      Есть один use case, когда такое может пригодиться. Когда мы не знаем, какого класса у нас объект, но хотим взять у него константу или статику. Но что-то мне кажется, что это больше «пахнет» ошибкой проектирования, чем реальной необходимостью…
        +2
        Я не сторонник публичных свойств как статических так и нет. Но они есть и к ним можно таким образом обратиться, поэтому я и показал это. Не более.

        Константы пишутся большими буквами, поэтому ошибиться будет сложно. Не обязательно не знать класс объекта, чтобы использовать пользоваться таким подходом.

        Например из zf2.

            public function __construct(InternalType\AbstractTypeObject $dictionary, \SplObjectStorage $processedDictionaries = null)
            {
                if ($dictionary->getType() != InternalType\AbstractTypeObject::TYPE_DICTIONARY) {
                    throw new Pdf\Exception('$dictionary mast be an indirect dictionary object.');
                }
        


        Можно заменить на.

            public function __construct(InternalType\AbstractTypeObject $dictionary, \SplObjectStorage $processedDictionaries = null)
            {
                if ($dictionary->getType() != $dictionary::TYPE_DICTIONARY) {
                    throw new Pdf\Exception('$dictionary mast be an indirect dictionary object.');
                }
        


        На мой взгляд читаемость не снизилась, а может быть даже и повысились. Ведь сразу видно, что это константа класса именно этого объекта.

        При переименовании класса, при таком подходе, потребуется внести меньше измененей.
          +3
          По мне так, это
          $dictionary->getType() != $dictionary::TYPE_DICTIONARY
          нужно заменять на
          $dictionary->isDictionary()
            +1
            Я тоже так подумал. С другой стороны количество констант может быть достаточно велико (в данном случае 8) и добавлении большого количества таких методов будут замусоривать класс, а новых возможностей не добавит. Я думаю, что это дело вкуса.
          0
          Переопределение статики в наследниках? Правда реальный пример только вымученный приходит в голову- необходимо получить фабричным статическим методом новый объект того же класса, что и параметр метода.
            +1
            Такое может быть. Взять хотя бы Активную запись, где для каждой таблицы свой класс. У всех этих классов может быть своя константа с именем таблицы в БД.
            0
            Кстати, чуть не забыл, статические методы можно вызывать и через "->".: )
            0
            Помимо
            $object::static_method()

            работает также и
            $string::static_method()

            с именем класса в $string, php же, надо же и так, и сяк… :)
              0
              Тут скрываются некоторые нюансы с namespace.

              Класс для экспериментов.
              namespace foo;
              
              class bar{
                  const BAZ = 'baz';
                  }
              


              Так работать не будет.
              $string = 'bar';
              echo $string::BAZ; // Fatal error: Class 'bar' not found
              


              А вот так будет.
              $string = __NAMESPACE__.'\bar';
              echo $string::BAZ; // baz
              
              $string = 'foo\bar';
              echo $string::BAZ; // baz
              

            Only users with full accounts can post comments. Log in, please.