Pull to refresh

Comments 31

есть проблема – анонимную функцию никак не вызвать

Серьёзно?

Серьёзно. В примере с этим комментарием функция бесполезна

а как же?

(function ($s) { 
    echo $s;
})('123');

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

И в целом абзац про iife стоит добавить. Спасибо за комментарий)

По PSR кроме того, что открывающая кавычка не на новой строке. Это сделано для удобства чтения кода

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

Оно непривычное, поэтому неудобное.

Они неудобны для чтения на мобильных устройствах, так как одна кавычка занимает целую строку, а на мобильных устройствах строк мало.

Я пишу код под разные стандарты и поддерживаю единообразие с помощью инструментов стат анализа.

В рамках данной статьи обсуждение стандартов написания кода вообще не имеет смысла.

Очень крутая статья.

Правда много объектных нюансов.

Я бы ещё добавил сюда пару абзацов про области видимости (namespace), и что с ними тоже можно играться при построении грамотного процедурного кода.

Вспомнился небольшой забавный проектик, когда я пробовал переписать Symfony на процедурный стиль с целью более глубокого изучения symfony и попыткой доказать, что без ООП тоже можно жить: git

Спасибо!

А можете подробнее расписать про комбинацию функций и областей видимости? Мне только обычный импорт вспоминается

Возможно я употребил неправильную терминологию. В доках на русском это называется пространства имён.

Ну и суть в изоляции имён функций, что бы небыло конфликтов, наприер с импортируемыми библиотеками.

Например a.php:

<?php

namespace my\functions;

function hello() {
  echo "world";
}

b.php:

<?php

use function \my\functions\hello as privet;

include("a.php");

\my\functions\hello(); //world

privet(); //world

hello(); //PHP Fatal error:  Uncaught Error: Call to undefined function hello() in b.php:11

Статья, на мой взгляд в целом хорошая и нужная.

Вот только я бы написал про про строгую типизацию поподробнее. Она всё-таки, целиком относится именно к функциям. Тем более что запустив пример createMessage(123, false)читатель не получит никакого InvalidArgumentException, а в статье не объясняется, как его получить.

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

Тем более что запустив пример createMessage(123, false) читатель не получит никакого InvalidArgumentException

Читатель получит syntax error, unexpected end of file, поскольку отсутствует точка с запятой.

Спасибо за содержательный комментарий!

Типизацию изначально вообще не думал упоминат, но в моих примерах она есть, поэтому затронута в статей, но без подробностей. Про типизацию в PHP планирую рассказать отдельно в будущем и сослаться из этой статьи для тех, кому интересно

Про точность терминов - согласен. Поправлю

Окей, не хотите писать про типизацию - дело ваше. Но оставлять в статье неверную информацию тоже не стоит. Надо или дописать одну строчку, поясняющую, как получить эту ошибку, или не писать про неё вовсе. И поправить синтаксис.

Полезная публикация! Спасибо.

И про типизацию я бы почитал с удовольствием. Думаю многим будет интересно когда целесообразно использовать phpdoc.

Типизация в современном PHP не имеет никакого отношения к phpdoc.
При включённом strict_types заданные в контракте функции типы аргументов и результата контролируются в момент исполнения кода и их несоответствие приводит к ошибке.
Комментарии phpdoc нужны для разработчика. Они общепринятым способом описывают не только типы, но и назначение аргументов и результата функции и могут содержать информацию о поведении функции. Эта информация может использоваться IDE для показа подсказок. При этом несоответствие типов в phpdoc самим PHP не контролируется и проверяется, как правило, статическим анализатором (возможно, встроенным в IDE).

Спасибо, полностью согласен с вами. Конечно, в первую очередь интересует контроль типов статическим анализатором из IDE (пользуемся VSCode). Ловить исключение после запуска - это не так интересно) А что касается phpdoc, то там есть где можно мысли развернуться, например, описание возвращаемой структуры данных из функции. В общем, пусть автор знает, что мне это интересно))

PHPdoc круто работает в связке со стат анализом от phpstan или psalm. Можно описывать типы более подробно (non-empty-string вместо string например), использовать дженерики. И проверять код на ошибки во время CI

Чего только люди не придумают, лишь бы компиляторами не пользоваться…. Может пора уже завезти в язык фичу, которая будет эмулировать компилятор и проверку типов делать вместо всех этих костылей?

Язык скриптовый, поэтому компиляции нет и не будет, иначе полная потеря обратной совместимости.

Но если очень хочется, то есть KPHP от VK - эта версия компилируемая, по набору фич соответствует 8.1 версии

А почему обязательно в язык? В чем принципиальная разница со сторонним инструментом, который прекрасно "эмулирует компилятор и делает проверку типов"?

Такая функция называется анонимной ведь у нее нет имени. Еще в PHP такие функции называют замыканиями или closure.

Анонимная функция и замыкание - это немного разные вещи. Кстати, это отличный вопрос для собеседования, чтобы понять уровень PHP разработчика. В интернете постоянно вижу, что люди не видят разницу между этими понятиями.

Ну я же говорю - это отличный вопрос для собеседования, чтобы понять уровень разработчика)) Погуглите, что такое замыкание и почему оно так называется. После этого погуглите ключевое слово, которое в PHP из анонимной функции делает замыкание. После этого вы поймёте, что нельзя все анонимные функции называть замыканиями, так как они не работают как замыкания по умолчанию.

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

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

Ну, это вы авторам PHP скажите, что нельзя. Они решили, что в PHP все анонимные функции являются замыканиями. А уж привязывать к ним переменные или нет и как именно привязывать - по значению или по ссылке - это дело разработчика.

Ну, это вы авторам PHP скажите, что нельзя. Они решили, что в PHP все анонимные функции являются замыканиями.

Мне кажется, что это какая-то путаница, связанная с тем, что все анонимные функции являются экземплярами класса, который называется Closure (замыкание). То есть они как бы замыкания, но по факту не замыкания, если не использовать use.

для импорта нужно явно указывать переменные

Не обязательно. Есть вариант со стрелочными функциями: using variables from the parent scope is always automatic

Еще есть способ создать Closure:

<?php

declare(strict_types=1);

readonly class Test
{
    private function __construct(private int $a, private int $b)
    {
    }

    public static function foo($a, $b): callable
    {
        $result = new self($a, $b);

        return $result->bar(...);
    }

    public function bar(int $c): int
    {
        return $this->a + $this->b + $c;
    }
}

echo Test::foo(1, 2)(3);

Это не замыкание. Для замыкания в классическом смысле функция bar должна создаваться внутри функции foo и иметь полный доступ к лексическому окружению последней, например, внутри bar должна быть доступна переменная $result из foo.

Тогда уж так:

function sum(int $a): callable|int  {
    $add = function (?int $b = null) use (&$add, &$a): callable|int {
        if ( ! is_null($b)) {
            $a += $b;

            return $add;
        }

        return $a;
    };

    return $add;
}

echo sum(1)(2)(3)(4)(); //10

Sign up to leave a comment.

Articles