Статьи

Состояние функционального программирования в PHP

С появлением Javascript и таких языков, как Python и Ruby, функциональное программирование становится все более распространенным явлением. Кажется, даже Java в следующих версиях получит замыкания , так что из-за этого не хватает PHP или внутри него скрыт нереализованный потенциал?

Динамическая отправка

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

function add($a, $b) { return $a + $b; } $add = "add"; $add(2, 8); // return 10 

В отличие от языков с поддержкой функций первого класса , переменная $add не является специальным типом — это просто строка, которая оценивается в контексте. Это может быть просто завернутый eval, но внешне он работает аналогично, как только функция была объявлена.

Также возможно явно вызвать ссылку на функцию с помощью call_user_func . Это интересно, потому что он принимает различные типы аргументов, что позволяет вызывать метод объекта. Подробнее об этом через минуту.

Обязательное состояние

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

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

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

 $add2 = curry($add, 2); // returns a new function reference, to add(), bound with 2 as the first argument $add2(8); // return 10 

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

Реализация карри

Не вдаваясь в подробности, есть два способа, карри можно реализовать в PHP.

Для более подробного объяснения взгляните на приложение с частичной функцией в PHP .

Взвешивание вариантов

Глядя на синтаксис, переменные-переменные имеют гораздо более функциональное «чувство», чем командный объект. Псевдотип обратного вызова позволяет ссылаться на имя объекта + метода, но даже если это поддерживается внутренними функциями PHP, он становится громоздким в пользовательском земельном коде. Если объект команды ощущается как функциональное программирование с синтаксисом ООП, то call_user_func напоминает функциональное программирование с процедурным синтаксисом.

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

В заключение

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

Другая идея, может быть дополнение уровня языка к PHP. Нам нужен способ сделать все обратные вызовы вызываемыми с помощью синтаксиса переменная-переменная. Я думаю, что это можно поддержать с помощью магического метода. Если бы объект должен был использоваться как функция, и он реализовал указанный магический метод, метод был бы вызван. С точки зрения дизайна, он прекрасно __call бы с другими магическими методами, такими как __call и friends.

Объявление функций

Еще одним ограничением, которое может быть устранено на уровне языка, является вопрос объявления функций в первую очередь. В настоящее время функции должны быть объявлены в глобальной области видимости или с помощью скрытой функции create_function . Были некоторые попытки улучшить это в команде php-internals, так что, может быть, нам повезло бы увидеть это в PHP 6?