Pull to refresh

Comments 70

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

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

однако, один вопрос в статье упущен (или мне показалось?): наследование статических методов и полей.
1. можно ли вызывать такие методы из потомка?
2. можно ли перекрывать такие методы, и как добраться до метода суперкласса?
3. время жизни статических полей?
4. доступны ли во время выполнения конструктора\деструктора?
5. что, если выполним два одновременных запроса к пхп, увидим ли мы одинаковые значение статических полей, или разные?
6. то же, что и 5¸только в разное время?
7. что, если обращаемся к статическому методу по нуллевой ссыле? (типичный вопрос для джава-юниора)
1) да, через через self/static
2) да, да, через parent
3) = времени жизни скрипта
4) да
5) разные.
6) разные.
7) в таком смысле в PHP ссылок нет
Потому что bolk не прав. Зависит от того, что значит «запроса к пхп». Изначально все зависит от реализации, может быть в статических полях константы — и мы всегда увидим одинаковые значения. Вероятно вопрос в том, сохраняются ли значения между разными запросами вида: запрос — php отработал — ответ, тогда нет, не сохранятся. А если php запущен, как демон, то сохранятся.
Так что вопрос идиотский и ответ на него тоже не понятный.
Ответ на вопрос всегда даётся в общем случае. В общем случае там разные значения. Я примерно понимаю о чём спрашивает Lure_of_Chaos, потому что я не припомню больше языков в вебе, которые работали бы как ПХП — умирали между запросами. А у него вопрос явно относится к разделяемым между различными обработчиками значениям.

Да, есть попытки привинчивания к PHP «честного» FastCGI или WSGI, но в данном случае постоянность значений не обеспечивается свойством статичных переменных, поэтому и тут мой ответ — «разные».
Я может глупость скажу, может чего-то не знаю. Но вроде Perl, Ruby, Python, PHP умирают между запросами, если они выполняются в обычном контексте веб-сервера.
Про Руби не знаю, а у Перла есть «честный» FastCGI, «Пайтон» же чаще всего пускают через WSGI.
что значит «в статических полях константы»?
Это будут разные поля, не одно и то же. А значение может быть какое угодно, хотите будет разное, хотите одинаковое.
2) — через имя класса, из которого хотите вытащить статический метод. parent:: работает только в контексте вызова метода объекта
однако, один вопрос в статье упущен (или мне показалось?)

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

P.S. Статья хорошая, не подумайте. Автору спасибо
А вы копайте, копайте глубже ))) Не копая не поймешь — цитирует собеседуемый статью, или действительно понимает смысл произносимых слов.
UFO just landed and posted this here
А откуда бы вы хотели чтоб человек черпал информацию в том числе по static в php? Я думаю это не проблема конкретно этой статьи, а вообще образования, конечно кто-то просто зазубрит что-то, что от него требует, а кто-то прочитает официальный мануал, прочитает несколько таких статей, попробует что-то сделать сам и усвоит знания. И я думаю 1 из 5 не так уж плохо, вот серьёзно :)
Я согласен ) Вопрос лишь в том что 4 из 5 перед собеседованием вместо теории и мануалов читают мануал как пройти собеседование по PHP.
А вы на собеседованиях ставите условие, чтобы ответ был более-менее уникальным? Тогда уж лучше тестовое задание давать, вместо этой теории.
Нет просто если мы слышим что человек цитирует подобную статью мы просим перефразировать ответ. Задание к сожалению меньше выявляет проблем. Лучше комплекс.
Скажите, а вы в своем «обыденном» коде как часто используете статические локальные переменные?
Бывает использую в рекурсивных функциях, например, для обработки древовидных структур, когда нужна общая переменная в процессе обработки. Ее можено либо передавать как аргумент, либо сделать глобальной, либо статической. Мне больше нравится последнее.
Ну в принципе ее можно сделать членом класса еще :)
Конечно, я просто думал, что вы речь ведете только про static относительно функций, а не методов классов и объектов.
нельзя, если древовидная структура — это скомпонированное древовидное множество из одной иерархии класса, но в таком случае лучше проходить каким-то посетителем
Мы тоже не часто используем их, но есть места, где они спасают. Плохо только одно, когда их начинает писать тот, кто не понимает как они работают.
Не часто. Ровно также, как нечастно использую, скажем, ссылки. Или интерфейс ArrayAccess.
Но это не значит, что я имею право не знать о такой возможности.
Вообще эта вещь очень удобна для кэширования результатов выполнение функции, поэтому раньше когда программировал функционально частенько применял, с переходом на ООП в методах применяю редко по причине описанной в статье — легко выстрелить в ногу.
Прошу прощения, не хочу показаться занудой, но зачем в коде:

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

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

echo перед вызовом функции foo?
UFO just landed and posted this here
Результат тот же, но echo — не print хотя бы по тому, что echo — конструкция языка, а print — функция, хоть внутри php source и имеют вызов одного функционала добавления строки в буффер вывода. Всё же они работают немного по-разному.
Например: сделайте
echo (echo "string");

и
echo (print "string");
print тоже языковая конструкция, а не функция.
Отличия
— print всегда вернет 1, а еcho ничего не возвращает.
— print допускает только один параметр, а echo несколько через запятую
echo не просто не возвращает (функция, не возвращающяя значения в php при присвоении даст null), выражение вызывает fatal error при попытке присвоить результат echo.
UFO just landed and posted this here
В PHP переменные локальны. Это значит, что переменная, определенная и получившая значение внутри функции (метода), существует только во время выполнения этой функции (метода). При выходе из метода локальная переменная уничтожается, а при повторном входе — создается заново. В коде выше такой локальной переменной является переменная $a — она существует только внутри функции foo() и каждый раз при вызове этой функции создается заново

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

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

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

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

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

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

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

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

Потому что именно собеседование для многих заменяет экзамен на профессионализм. Рядовой разработчик на PHP зачастую только на собеседовании, к стыду своему, понимает, что он как тот Джон Сноу — имеет в портфолио десяток проектов, кучу фреймворков и паттернов, но ничего не знает…
Честно говоря, я и сам отношусь к подобным вопросам скорее негативно. Но это не отменяет того факта, что они просто есть.
Интересно, только я не знал первый вариант использования «static» (создание статической локальной переменной)? Наверное, минус постоянной ОО разработки — с некоторыми нюансами языка, проявляющимися при процедурном программировании, просто никогда не сталкиваешься.
Молодые многие не знают по опыту, это этакий олдскул.
А по-моему, это ненужная конструкция. Если тебе нужна волшебная константа, то лучше объявить её прямо в классе, чтобы она всегда на виду была, потому что это волшебная зависимость.
Некоторые вещи про php лучше не знать. Например то что есть трюк вызывать protected методы не только из вашего класса )
Имеется ввиду из классов, не наследующих данный? Если так, то заинтриговали :) Поделитесь ссылкой?
Если мне не изменяет память то достаточно что бы у классов был общий родитель. Но не обязательно наследовать нужный класс.
Я думаю 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());


Да, я имел ввиду вызов из других обьектов. И я ошибся с общим родителем, класс надо наследовать, или хотя бы наследовать тот класс в иерархии, который содержит нужный нам метод/свойство.
Вот так тоже можно:
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);
Забавная «фича». Век живи — век учись.
Ну скажите как интересно, описать что означает static в типовом ООП, причём так, будто какие-то неожиданные свойства открылись. А реально неожиданное — это только «позднее связывание» с заменой $self на static. Правда практическое применение придумать что-то не выходит у меня.

Автору спасибо — «размял» немного мозг, но лучше было бы написать, что такое static и почему от него ожидают именно того поведения, которое приведено в статье.
P.S. На всякий случай: ключевое слово статик вовсе не связано с «Значение помеченной таким образом переменной сохраняется после окончания работы функции» — это следствие.
А реально неожиданное — это только «позднее связывание» с заменой $self на static.

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

Поэтому я и пишу такие статьи. Чтобы «неожиданностей» в мануале по языку, за знание которого вам платят деньги, было поменьше.
«Неожиданное» в смысле «классических» ООП языков. Ну никак из смысла static не вытекает возможность сделать ссылку на класс-потомок сделать доступной в родительском классе. Обычно просто используются виртуальные методы и т.п.
Скорее просто неудачный выбор ключевого слова.
Согласитесь, что например children::method() или current::method() было бы гораздо проще запоминать и объяснять начинающим, нежели static::method()
именно static и ведет себя так, как должен вести себя в классических ОО-языках, для меня было большей неожиданностью поведение self когда я узнал о позднем связывании. потому следует понимать когда нужно использовать self, а когда static. как по мне, то использование static более прозрачно, а вот self использовать уже когда это дейсвительно нужно оправдано
new static(); самое частое использование
Странно, столько мнений, но никто не сказал, что не стоит увлекаться статикой. В любой книге про ООП написано, что она портит архитектуру — делает код нетестируемым и ломким, а классы тесно связаными друг с другом. Мне кажется именно об этом стоит говорить на собеседовании.
Дело в том, что это мнение про «не стоит увлекаться» само по себе ничего не значит, если вы не способны это мнение обосновать.

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

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

P.S. Мнение «статика — всегда плохо» как минимум спорно. Есть ORM где, например, статические методы класса сущности работают с таблицей сущностей, динамические — с конкретной записью в этой таблице. Это тоже плохо? Почему?
Статика, глобальные переменные это кошмар при написании unit тестов.
Тесты должны исполняться независимо друг от друга.
Чтобы быть уверенным, что никто до вас не вызывал функцию foo, вам придется перезапускать php процесс перед выполнением каждого теста.
function foo() {
  static $a = 0;
  echo $a;
  $a = $a + 1;
}

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

На самом деле есть ещё одно несказанное использование static, доступное по умолчанию с PHP 5.4:


class A
{
    private $item;

    public function foo()
    {
        // здесь колбэк по умолчанию замыкается на this контекста, 
        // с которого он был вызван (по умолчанию с PHP 5.4)
        $callable = function () {
            return $this->item * 2;
        }
    }

    public function bar()
    {
        // однако если указать static, то замыкаться на this вызванного контекста 
        // колбэк уже не будет
        $callable = static function () {
            return $this->item * 2; // кинет fatal error
        }
    }
}
Для точности я бы рекомендовал термин «анонимная функция» или «лямбда-функция», а не «коллбэк». Не всякая функция обратного вызова должна быть анонимной, не всякая лямбда применяется как «коллбэк».

И да, разумеется, спасибо за хорошее дополнение. Не стал его упоминать в статье в виду всё-таки экзотичности применения.
Sign up to leave a comment.

Articles

Change theme settings