Не секрет, что на собеседованиях любят задавать каверзные вопросы. Не всегда адекватные, не всегда имеющие отношение к реальности, но факт остается фактом — задают. Конечно, вопрос вопросу рознь, и иногда вопрос, на первый взгляд кажущийся вам дурацким, на самом деле направлен на проверку того, насколько хорошо вы знаете язык, на котором пишете.

image

Попробуем разобрать «по косточкам» один из таких вопросов — что значит слово «static» в PHP и зачем оно применяется?

Ключевое слово static имеет в PHP три различных значения. Разберем их в хронологическом порядке, как они появлялись в языке.

Значение первое — статическая локальная переменная


function foo() {
  $a = 0;
  echo $a;
  $a = $a + 1;
}

foo(); // 0
foo(); // 0
foo(); // 0


В PHP переменные локальны. Это значит, что переменная, определенная и получившая значение внутри функции (метода), существует только во время выполнения этой функции (метода). При выходе из метода локальная переменная уничтожается, а при повторном входе — создается заново. В коде выше такой локальной переменной является переменная $a — она существует только внутри функции foo() и каждый раз при вызове этой функции создается заново. Инкремент переменной в этом коде бессмысленен, поскольку на следующей же строчке кода функция закончит свою работу и значение переменной будет потеряно. Сколько бы раз мы не вызвали функцию foo(), она всегда будет выводить 0…

Однако всё меняется, если мы перед присваиванием поставим ключевое слово static:

function foo() {
  static $a = 0;
  echo $a;
  $a = $a + 1;
}

foo(); // 0
foo(); // 1
foo(); // 2


Ключевое слово static, написанное перед присваиванием значения локальной переменной, приводит к следующим эффектам:
  1. Присваивание выполняется только один раз, при первом вызове функции
  2. Значение помеченной таким образом переменной сохраняется после окончания работы функции
  3. При последующих вызовах функции вместо присваивания переменная получает сохраненное ранее значение

Такое использование слова static называется статическая локальная переменная.

Подводные камни статических переменных

Разумеется, как всегда в PHP, не обходится без «подводных камней».

Камень первый — статической переменной присваивать можно только константы или константные выражения. Вот такой код:
static $a = bar();

с неизбежностью приведет к ошибке парсера. К счастью, начиная с версии 5.6 стало допустимым присвоение не только констант, но и константных выражений (например — «1+2» или "[1, 2, 3]"), то есть таких выражений, которые не зависят от другого кода и могут быть вычислены на этапе компиляции

Камень второй — методы существуют в единственном экземпляре.
Тут всё чуть сложнее. Для понимания сути приведу код:
class A {
  public function foo() {
    static $x = 0;
    echo ++$x;
  }
}

$a1 = new A;
$a2 = new A;

$a1->foo(); // 1
$a2->foo(); // 2
$a1->foo(); // 3
$a2->foo(); // 4

Вопреки интуитивному ожиданию «разные объекты — разные методы» мы наглядно видим на этом примере, что динамические методы в PHP «не размножаются». Даже если у нас будет сто объектов этого класса, метод будет существовать лишь в одном экземпляре, просто при каждом вызове в него будет пробрасываться разный $this.

Такое поведение может быть неожиданным для неподготовленного к нему разработчика и послужить источником ошибок. Нужно заметить, что наследование класса (и метода) приводит к тому, что всё-таки создается новый метод:

class A {
  public function foo() {
    static $x = 0;
    echo ++$x;
  }
}

class B extends A {
}

$a1 = new A;
$b1 = new B;

$a1->foo(); // 1
$b1->foo(); // 1
$a1->foo(); // 2
$b1->foo(); // 2


Вывод: динамические методы в PHP существуют в контексте классов, а не объектов. И только лишь в рантайме происходит подстановка "$this = текущий_объект"

Значение второе — статические свойства и методы классов


В объектной модели PHP существует возможность задавать свойства и методы не только для объектов — экземпляров класса, но и для класса в целом. Для этого тоже служит ключевое слово static:

class A {
  public static $x = 'foo';
  public static function test() {
    return 42;
  }
}

echo A::$x; // 'foo'
echo A::test(); // 42

Для доступа к таким свойствам и методам используются конструкции с двойным двоеточием («Paamayim Nekudotayim»), такие как ИМЯ_КЛАССА::$имяПеременной и ИМЯ_КЛАССА:: имяМетода().

Само собой разумеется, что у статических свойств и статических методов есть свои особенности и свои «подводные камни», которые нужно знать.

Особенность первая, банальная — нет $this. Собственно это проистекает из самого определения статического метода — поскольку он связан с классом, а не объектом, в нём недоступна псевдопеременная $this, указывающая в динамических методах на текущий объект. Что совершенно логично.

Однако, нужно знать, что в отличие от других языков, PHP не определяет ситуацию «в статическом методе написано $this» на этапе парсинга или компиляции. Подобная ошибка может возникнуть только в рантайме, если вы попытаетесь выполнить код с $this внутри статического метода.

Код типа такого:
class A {
  public $id = 42;
  static public function foo() {
    echo $this->id;
  }
}

не приведет ни к каким ошибкам, до тех пор, пока вы не попытаетесь использовать метод foo() неподобающим образом:
$a = new A;
$a->foo();
(и сразу получите «Fatal error: Using $this when not in object context»)

Особенность вторая — static не аксиома!
class A {
  static public function foo() {
    echo 42;
  }
}

$a = new A;
$a->foo();

Вот так, да. Статический метод, если он не содержит в коде $this, вполне можно вызывать в динамическом контексте, как метод объекта. Это не является ошибкой в PHP.

Обратное не совсем верно:
class A {
  public function foo() {
    echo 42;
  }
}

A::foo();

Динамический метод, не использующий $this, можно выполнять в статическом контексте. Однако вы получите предупреждение «Non-static method A::foo() should not be called statically» уровня E_STRICT. Тут решать вам — или строго следовать стандартам кода, или подавлять предупреждения. Первое, разумеется, предпочтительнее.

И кстати, всё написанное выше относится только к методам. Использование статического свойства через "->" невозможно и ведет к фатальной ошибке.

Значение третье, кажущееся самым сложным — позднее статическое связывание


Разработчики языка PHP не остановились на двух значениях ключевого слова «static» и в версии 5.3 добавили еще одну «фичу» языка, которая реализована тем же самым словом! Она называется «позднее статическое связывание» или LSB (Late Static Binding).

Понять суть LSB проще всего на несложных примерах:

class Model {
  public static $table = 'table';
  public static function getTable() {
    return self::$table;
  }
}

echo Model::getTable(); // 'table'

Ключевое слово self в PHP всегда значит «имя класса, где это слово написано». В данном случае self заменяется на класс Model, а self::$table — на Model::$table.
Такая языковая возможность называется «ранним статическим связыванием». Почему ранним? Потому что связывание self и конкретного имени класса происходит не в рантайме, а на более ранних этапах — парсинга и компиляции кода. Ну а «статическое» — потому что речь идет о статических свойствах и методах.

Немного изменим наш код:

class Model {
  public static $table = 'table';
  public static function getTable() {
    return self::$table;
  }
}

class User extends Model {
  public static $table = 'users';
}

echo User::getTable(); // 'table'


Теперь вы понимаете, почему PHP ведёт себя в этой ситуации неинтуитивно. self был связан с классом Model тогда, когда о классе User еще ничего не было известно, поэтому и указывает на Model.

Как быть?

Для решения этой дилеммы был придуман механизм связывания «позднего», на этапе рантайма. Работает он очень просто — достаточно вместо слова «self» написать «static» и связь будет установлена с тем классом, который вызывает данный код, а не с тем, где он написан:
class Model {
  public static $table = 'table';
  public static function getTable() {
    return static::$table;
  }
}

class User extends Model {
  public static $table = 'users';
}

echo User::getTable(); // 'users'


Это и есть загадочное «позднее статическое связывание».

Нужно отметить, что для большего удобства в PHP кроме слова «static» есть еще специальная функция get_called_class(), которая сообщит вам — в контексте какого класса в данный момент работает ваш код.

Удачных собеседований!

Список полезных ссылок на мануал:

Комментарии (67)


  1. Lure_of_Chaos
    05.06.2015 15:10

    Все становится просто супер интуитивно понятным, если понять, что значит static:
    — привязка к «объекту» класса, а его не его реализующего объекта, т.е. для всех объектов класса
    — привязка происходит в момент загрузки класса, не раньше («загружен, но не вызван») и не позже («выполнился коллбек-конструктор класса»)

    все относится как к переменным, так и методам объекта.

    однако, один вопрос в статье упущен (или мне показалось?): наследование статических методов и полей.
    1. можно ли вызывать такие методы из потомка?
    2. можно ли перекрывать такие методы, и как добраться до метода суперкласса?
    3. время жизни статических полей?
    4. доступны ли во время выполнения конструктора\деструктора?
    5. что, если выполним два одновременных запроса к пхп, увидим ли мы одинаковые значение статических полей, или разные?
    6. то же, что и 5?только в разное время?
    7. что, если обращаемся к статическому методу по нуллевой ссыле? (типичный вопрос для джава-юниора)


    1. bolk
      05.06.2015 16:34
      +1

      1) да, через через self/static
      2) да, да, через parent
      3) = времени жизни скрипта
      4) да
      5) разные.
      6) разные.
      7) в таком смысле в PHP ссылок нет


      1. Ugputu
        06.06.2015 10:26

        почему 5 и 6 разные?


        1. hell0w0rd
          06.06.2015 11:51

          Потому что bolk не прав. Зависит от того, что значит «запроса к пхп». Изначально все зависит от реализации, может быть в статических полях константы — и мы всегда увидим одинаковые значения. Вероятно вопрос в том, сохраняются ли значения между разными запросами вида: запрос — php отработал — ответ, тогда нет, не сохранятся. А если php запущен, как демон, то сохранятся.
          Так что вопрос идиотский и ответ на него тоже не понятный.


          1. bolk
            06.06.2015 11:59
            +2

            Ответ на вопрос всегда даётся в общем случае. В общем случае там разные значения. Я примерно понимаю о чём спрашивает Lure_of_Chaos, потому что я не припомню больше языков в вебе, которые работали бы как ПХП — умирали между запросами. А у него вопрос явно относится к разделяемым между различными обработчиками значениям.

            Да, есть попытки привинчивания к PHP «честного» FastCGI или WSGI, но в данном случае постоянность значений не обеспечивается свойством статичных переменных, поэтому и тут мой ответ — «разные».


            1. Ugputu
              06.06.2015 21:11

              Я может глупость скажу, может чего-то не знаю. Но вроде Perl, Ruby, Python, PHP умирают между запросами, если они выполняются в обычном контексте веб-сервера.


              1. bolk
                07.06.2015 21:13

                Про Руби не знаю, а у Перла есть «честный» FastCGI, «Пайтон» же чаще всего пускают через WSGI.


          1. Ugputu
            06.06.2015 21:12

            что значит «в статических полях константы»?


        1. velezh
          06.06.2015 12:01

          Это будут разные поля, не одно и то же. А значение может быть какое угодно, хотите будет разное, хотите одинаковое.


      1. nikita2206
        08.06.2015 16:53

        2) — через имя класса, из которого хотите вытащить статический метод. parent:: работает только в контексте вызова метода объекта


  1. AlexLeonov Автор
    05.06.2015 15:15

    однако, один вопрос в статье упущен (или мне показалось?)

    Ну всего в одну статью не впихнёшь, я бы хотел серию сделать с подзаголовком «Готовимся к собеседованию». Часть ваших вопросов интересна, часть — не имеет смысла в PHP )))


  1. stavinsky
    05.06.2015 15:30
    +4

    Ох как мне не нравятся подобные статьи, точнее их последствия. Мы один раз долго не могли понять почему серия из 5ти соискателей отвечает на одинаковый вопрос слово в слово. И вроде бы правильно отвечает, а если копнуть глубже 4 из 5 не смогли развить тему и чуть дальше. После поиска в гугле нашли подобную статью и ответ на наш вопрос в ней. Долго смеялись и просили на следующих собеседованиях отвечать другими терминами.

    P.S. Статья хорошая, не подумайте. Автору спасибо


    1. AlexLeonov Автор
      05.06.2015 15:50

      А вы копайте, копайте глубже ))) Не копая не поймешь — цитирует собеседуемый статью, или действительно понимает смысл произносимых слов.


    1. stardust_kid
      05.06.2015 19:09
      +2

      Значит вопрос скомпрометирован, надо генерировать новый.


    1. plus
      06.06.2015 08:34
      +2

      А откуда бы вы хотели чтоб человек черпал информацию в том числе по static в php? Я думаю это не проблема конкретно этой статьи, а вообще образования, конечно кто-то просто зазубрит что-то, что от него требует, а кто-то прочитает официальный мануал, прочитает несколько таких статей, попробует что-то сделать сам и усвоит знания. И я думаю 1 из 5 не так уж плохо, вот серьёзно :)


      1. stavinsky
        08.06.2015 11:31

        Я согласен ) Вопрос лишь в том что 4 из 5 перед собеседованием вместо теории и мануалов читают мануал как пройти собеседование по PHP.


    1. Vizakenjack
      06.06.2015 10:52

      А вы на собеседованиях ставите условие, чтобы ответ был более-менее уникальным? Тогда уж лучше тестовое задание давать, вместо этой теории.


      1. stavinsky
        08.06.2015 11:30

        Нет просто если мы слышим что человек цитирует подобную статью мы просим перефразировать ответ. Задание к сожалению меньше выявляет проблем. Лучше комплекс.


  1. guyfawkes
    05.06.2015 20:31
    +5

    Скажите, а вы в своем «обыденном» коде как часто используете статические локальные переменные?


    1. maximw
      05.06.2015 22:34

      Бывает использую в рекурсивных функциях, например, для обработки древовидных структур, когда нужна общая переменная в процессе обработки. Ее можено либо передавать как аргумент, либо сделать глобальной, либо статической. Мне больше нравится последнее.


      1. guyfawkes
        06.06.2015 11:51

        Ну в принципе ее можно сделать членом класса еще :)


        1. maximw
          06.06.2015 14:34

          Конечно, я просто думал, что вы речь ведете только про static относительно функций, а не методов классов и объектов.


        1. dvapelnik
          12.06.2015 09:04

          нельзя, если древовидная структура — это скомпонированное древовидное множество из одной иерархии класса, но в таком случае лучше проходить каким-то посетителем


    1. Rathil
      06.06.2015 02:01
      +1

      Мы тоже не часто используем их, но есть места, где они спасают. Плохо только одно, когда их начинает писать тот, кто не понимает как они работают.


    1. AlexLeonov Автор
      06.06.2015 12:42
      +1

      Не часто. Ровно также, как нечастно использую, скажем, ссылки. Или интерфейс ArrayAccess.
      Но это не значит, что я имею право не знать о такой возможности.


    1. annenkov
      06.06.2015 13:03

      Вообще эта вещь очень удобна для кэширования результатов выполнение функции, поэтому раньше когда программировал функционально частенько применял, с переходом на ООП в методах применяю редко по причине описанной в статье — легко выстрелить в ногу.


  1. XanderBass
    05.06.2015 22:48
    +4

    Прошу прощения, не хочу показаться занудой, но зачем в коде:

    function foo() {
    static $a = 0;
    echo $a;
    $a = $a + 1;
    }

    echo foo(); // 0
    echo foo(); // 1
    echo foo(); // 2

    echo перед вызовом функции foo?


    1. stychos
      06.06.2015 04:23

      Можно написать и echo(foo()), просто echo (она же print) — языковая конструкция, а не функция.


      1. romy4
        08.06.2015 15:42
        -1

        Результат тот же, но echo — не print хотя бы по тому, что echo — конструкция языка, а print — функция, хоть внутри php source и имеют вызов одного функционала добавления строки в буффер вывода. Всё же они работают немного по-разному.
        Например: сделайте

        echo (echo "string");
        

        и
        echo (print "string");
        


        1. maximw
          08.06.2015 15:55

          print тоже языковая конструкция, а не функция.
          Отличия
          — print всегда вернет 1, а еcho ничего не возвращает.
          — print допускает только один параметр, а echo несколько через запятую


          1. romy4
            08.06.2015 16:50
            +1

            echo не просто не возвращает (функция, не возвращающяя значения в php при присвоении даст null), выражение вызывает fatal error при попытке присвоить результат echo.


    1. stychos
      06.06.2015 04:27
      +1

      Впрочем, Вы правы, туплю-с, foo() ничего же не возвращает.


    1. AlexLeonov Автор
      06.06.2015 12:43
      +1

      Благодарю Вас, исправил.


  1. Rathil
    06.06.2015 01:56

    В PHP переменные локальны. Это значит, что переменная, определенная и получившая значение внутри функции (метода), существует только во время выполнения этой функции (метода). При выходе из метода локальная переменная уничтожается, а при повторном входе — создается заново. В коде выше такой локальной переменной является переменная $a — она существует только внутри функции foo() и каждый раз при вызове этой функции создается заново

    В целом да, но не всегда :)
    НО, конкретно в том примере, что приведен выше — да


  1. RinatUsmanov
    06.06.2015 10:21

    спасибо за статью!


  1. Razor
    06.06.2015 10:59
    +1

    И кстати, всё написанное выше относится только к свойствам. Использование статического свойства через "->" невозможно и ведет к фатальной ошибке.

    В первом предложении не должно быть «к методам» вместо «свойствам»?


    1. AlexLeonov Автор
      06.06.2015 12:39

      Да. Исправил, спасибо!


  1. NekR
    06.06.2015 11:28
    +1

    Вот я мимо проходил, статью не читал, но может надо готовиться к программированию на PHP, а не к собеседованию?


    1. guyfawkes
      06.06.2015 11:53

      В вопросах часто звучат нюансы, которые либо знаешь, потому что читал/сам ошибался и искал фикс/экспериментировал, либо нет, так как не приходилось использовать, и касается вопросов не только по PHP.


      1. NekR
        06.06.2015 12:06
        -1

        Абсолютно согласен, однако то что такие вопросы задают не значит что это хорошо/правильно. Сам на собеседования задавал такие вопросы, мне задавали их на собеседованиях. Когда подрос понял что это глупо. Но могу быть не прав, если у кого то есть веские аргументы в пользу такого подхода.


        1. AlexLeonov Автор
          06.06.2015 12:40

          Когда подрос понял что это глупо

          Не подскажете — что глупого в вопросах на знание языка, задаваемых кандидату на позицию разработчика на этом языке?


          1. NekR
            06.06.2015 12:56
            +2

            Я говорю не о знании языка, а конкретно о глупых вопросах именно на собеседовании, как их назвали в комментарии выше — «нюансах». Конечно нужно знать язык, в этом суть, но очень часто спрашивают о ситуациях которые встречаются ну очень редко или вообще могу не встретится человеку. Понятно что их тоже хорошо бы знать и они могут пригодиться, но если человек знает хорошо свою работу и вообще способный, то когда встретится тот самый нюанс, я думаю, он сможет с ним справиться. На крайний случай, если нет, то для этого и нужна команда и вообще все люди/программисты продолжают дальше учиться, даже когда уже знают достаточно.

            Ещё раз повторю, статью я не читал, меня взволновал заголовок и в следствии чего последовал вопрос. На счёт «нюансов» отвечаю так как про них заговорили в ответе к моему комментарию. Если же статья не про нюансы, а про другое, тогда мой первый вопрос на счёт заголовка до сих пор в силе.


            1. AlexLeonov Автор
              07.06.2015 11:50

              Если же статья не про нюансы, а про другое, тогда мой первый вопрос на счёт заголовка до сих пор в силе.

              Статья, с вашего позволения, не про «нюансы», к которым вы испытываете столь сложные чувства, а про систематизацию. Про собрать в одном месте всё, что касается одного ключевого слова языка и систематизировать эти знания.


              1. NekR
                07.06.2015 17:24
                +1

                Это здорово, но позвольте, вы так и не ответили тогда на вопрос «почему для собеседования?». Если это общие знания которые нужно знать любому разработчику что бы хорошо программировать на языке, почему не назвать статью «Изучаем <язык>: <тема статьи>»? Лично в моём понимании, если статья называется «для собеседования», то это значит что там говорится про то, что с очень маленькой вероятностью может пригодиться в реальной работе. Выглядит так, что контент этой статьи нужен будет людям только что бы пройти собеседование, а дальше могут забыть о нём и не пользоваться.

                > а про систематизацию. Про собрать в одном месте всё, что касается одного ключевого слова языка и систематизировать эти знания.

                Вы молодец что делаете это и к статье самой или к вам у меня претензий быть не может. Моё желание лишь понять, чем вы руководствовались когда называли это «для собеседования».


                1. AlexLeonov Автор
                  07.06.2015 17:29
                  +1

                  Это здорово, но позвольте, вы так и не ответили тогда на вопрос «почему для собеседования?»

                  Извините, не увидел вопроса.

                  Потому что именно собеседование для многих заменяет экзамен на профессионализм. Рядовой разработчик на PHP зачастую только на собеседовании, к стыду своему, понимает, что он как тот Джон Сноу — имеет в портфолио десяток проектов, кучу фреймворков и паттернов, но ничего не знает…


        1. guyfawkes
          06.06.2015 16:57

          Честно говоря, я и сам отношусь к подобным вопросам скорее негативно. Но это не отменяет того факта, что они просто есть.


  1. hospect
    06.06.2015 13:29

    Интересно, только я не знал первый вариант использования «static» (создание статической локальной переменной)? Наверное, минус постоянной ОО разработки — с некоторыми нюансами языка, проявляющимися при процедурном программировании, просто никогда не сталкиваешься.


    1. annenkov
      06.06.2015 17:25
      +2

      Молодые многие не знают по опыту, это этакий олдскул.


      1. godlin
        06.06.2015 18:09
        -3

        А по-моему, это ненужная конструкция. Если тебе нужна волшебная константа, то лучше объявить её прямо в классе, чтобы она всегда на виду была, потому что это волшебная зависимость.


    1. fear86
      06.06.2015 20:56

      Некоторые вещи про php лучше не знать. Например то что есть трюк вызывать protected методы не только из вашего класса )


      1. hospect
        07.06.2015 00:12

        Имеется ввиду из классов, не наследующих данный? Если так, то заинтриговали :) Поделитесь ссылкой?


        1. fear86
          07.06.2015 13:55

          Если мне не изменяет память то достаточно что бы у классов был общий родитель. Но не обязательно наследовать нужный класс.


        1. to0n1
          08.06.2015 23:40
          +1

          Я думаю fear86 говорит о следующем кейсе

          код
          <?php
          
          class firstClass
          {
              /** @var string */
              protected $message;
          
              public function __construct($message)
              {
                  $this->message = $message;
              }
          }
          
          class secondClass extends firstClass
          {
              /** @var firstClass */
              protected $firstClass;
          
              public function __construct(firstClass $firstClass)
              {
                  $this->firstClass = $firstClass;
              }
          
              public function accessProtected()
              {
                  return $this->firstClass->message;
              }
          }
          
          $a = new firstClass('Hello protected');
          $b = new secondClass($a);
          
          var_dump($b->accessProtected());
          
          


          1. fear86
            09.06.2015 00:08

            Да, я имел ввиду вызов из других обьектов. И я ошибся с общим родителем, класс надо наследовать, или хотя бы наследовать тот класс в иерархии, который содержит нужный нам метод/свойство.
            Вот так тоже можно:

            class a {
              protected function test()
              {
                return 'protected';
              }
            }
            
            class e extends a {
            }
            
            class c extends a {
              public function __call($name, $args)
              {
                return call_user_func_array(array(array_shift($args), $name), $args);
              }
            }
            
            $e = new e();
            $c = new c();
            echo $c->test($e);
            


          1. maximw
            09.06.2015 00:11

            Забавная «фича». Век живи — век учись.


      1. annenkov
        07.06.2015 01:19

        Тоже интересно, может все таки имелось ввиду вызывать не только из вашего объекта — php.net/manual/ru/language.oop5.visibility.php#language.oop5.visibility-other-objects, рефлекшены уж наверное тут не подразумевались.


  1. TimID
    07.06.2015 01:09

    Ну скажите как интересно, описать что означает static в типовом ООП, причём так, будто какие-то неожиданные свойства открылись. А реально неожиданное — это только «позднее связывание» с заменой $self на static. Правда практическое применение придумать что-то не выходит у меня.

    Автору спасибо — «размял» немного мозг, но лучше было бы написать, что такое static и почему от него ожидают именно того поведения, которое приведено в статье.


    1. TimID
      07.06.2015 01:13

      P.S. На всякий случай: ключевое слово статик вовсе не связано с «Значение помеченной таким образом переменной сохраняется после окончания работы функции» — это следствие.


    1. AlexLeonov Автор
      07.06.2015 11:52
      +1

      А реально неожиданное — это только «позднее связывание» с заменой $self на static.

      Эта возможность появилась лет пять назад, в 5.3. Она является основной многих современных фреймворков, например, можно сказать что Yii 2 обязан своему появлению переходу именно на 5.3 А для вас это вдруг неожиданность.

      Поэтому я и пишу такие статьи. Чтобы «неожиданностей» в мануале по языку, за знание которого вам платят деньги, было поменьше.


      1. TimID
        07.06.2015 23:46

        «Неожиданное» в смысле «классических» ООП языков. Ну никак из смысла static не вытекает возможность сделать ссылку на класс-потомок сделать доступной в родительском классе. Обычно просто используются виртуальные методы и т.п.


        1. AlexLeonov Автор
          08.06.2015 13:53

          Скорее просто неудачный выбор ключевого слова.
          Согласитесь, что например children::method() или current::method() было бы гораздо проще запоминать и объяснять начинающим, нежели static::method()


          1. dvapelnik
            13.06.2015 13:45

            именно static и ведет себя так, как должен вести себя в классических ОО-языках, для меня было большей неожиданностью поведение self когда я узнал о позднем связывании. потому следует понимать когда нужно использовать self, а когда static. как по мне, то использование static более прозрачно, а вот self использовать уже когда это дейсвительно нужно оправдано


    1. fear86
      07.06.2015 13:58

      new static(); самое частое использование


  1. karser
    08.06.2015 16:21

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


    1. AlexLeonov Автор
      08.06.2015 17:09
      +1

      Дело в том, что это мнение про «не стоит увлекаться» само по себе ничего не значит, если вы не способны это мнение обосновать.

      Что такое «не стоит увлекаться»? Почему? Только потому, что «в любой книге написано»? В чём проблема тестирования такого кода? Как эти проблемы решать?

      Видите, сколько сразу вопросов, которые вам зададут на приличном собеседовании?

      P.S. Мнение «статика — всегда плохо» как минимум спорно. Есть ORM где, например, статические методы класса сущности работают с таблицей сущностей, динамические — с конкретной записью в этой таблице. Это тоже плохо? Почему?


      1. karser
        11.06.2015 20:14

        Статика, глобальные переменные это кошмар при написании unit тестов.
        Тесты должны исполняться независимо друг от друга.
        Чтобы быть уверенным, что никто до вас не вызывал функцию foo, вам придется перезапускать php процесс перед выполнением каждого теста.

        function foo() {
          static $a = 0;
          echo $a;
          $a = $a + 1;
        }
        
        foo(); // 0
        foo(); // 1
        foo(); // 2
        


        1. AlexLeonov Автор
          11.06.2015 22:32

          Во-первых вы немного путаете. Предыдущий юзер имел в виду, под «статикой» статические методы классов все-таки.
          Во-вторых да, тесты должны выполняться независимо. Но с другой стороны архитектура может потребовать от вас некую «функцию с внутренним состоянием», чем бы это ни было, пусть даже это будет объект, который банально считает число вызовов своего определенного метода. И как быть? Как бы вы решили эту дилемму?