solit 2014, functional programming, Соловей Василий
DESCRIPTION
Василий Соловей, Солигорск. PHP-разработчик в в «Электронном Солигорске». «Минусы ООП на примере языка PHP». Development секция. Для разработчиков (начальный и средний уровень). 1. Что есть ООП (легкое повторение уже знакомого) 2. Лучше доверять авторитету мнения, чем мнению авторитета (во всем нужно разбираться основательно, а в ООП тем более) 3. Неизменная скупость в похвалах — верный признак посредственного ума (плюсы ООП) 4. Не все то солнышко, что блестит (основная часть доклада – минусы ООП) 5. Кто владеет информацией, тот владеет ситуацией (пояснение сути доклада: доклад не принижает и не умоляет достоинств ООП он создан расширить кругозор) «Начинать никогда не поздно!». Мотивационное выступление. На личном примере, я могу рассказать, что начинать никогда не поздно, и если есть желание – нет повода себе отказывать. 1. Путь в тысячу миль начинается с одного шага (с чего начать) 2. И на верном пути повстречаются распутья (как не сбиться с дороги начав) 3. Кто ты программист? (мой взгляд на программирование) 4. Успех – дитя настойчивостиTRANSCRIPT
Functional programming Важные аспекты функционального программирования
Начнём с терминов. Википедия определяет функциональное программирование как “парадигму программирования, в которой процесс вычисления трактуется как вычисление значений функций в математическом понимании последних”. В данном способе программирования главным объектом манипуляции являются функции, в то время как в императивном программировании главным принципом является последовательное выполнение команд для достижения желаемого результата.
Когда я сказал, что главным объектом манипуляции являются функции, я имел в виду, что с ними мы можем делать всё, что угодно: передавать как аргументы в другие функции, определять функции в функциях, использовать функции в качестве возвращаемых значений! В общем, кругом одни функции.
Теперь давайте подойдём ближе к некоторым особенностями функционального программирования.
Неизменность
Свойством неизменности обладают значения, которые не могут быть изменены. В PHP и многих других языках их называют константами.
Рекурсия
Рекурсия - это один из часто используемых приёмов в функциональном программировании. При императивном подходе, для прокрутки по массивам мы можем воспользоваться циклами for или foreach, записывая текущее значение во временную переменную. Из-за принципа “неизменности”, данный подход неприемлем для функционального программирования.
Предположим, что мы хотим получить сумму элементов массива (забудьте о array_sum()). При функциональном подходе, решение данной задачи будет выглядеть так:
1 <?php2 function sum($array) {3 if (empty($array))4 return 0;5 else6 return $array[0] + sum(array_slice($array, 1));7 }8 9 $total = sum(array(1, 2, 3)); // 6Если массив пустой, то сумма элементов будет равна 0. В случае если в массиве больше элементов, мы применяем рекурсию.
Чистые функции
Если функция никаким образом не меняет значения переменных, которые находятся за её пределами и не осуществляет действия по вводу/выводу данных в файл, базу данных и т.д., то такую функцию можно назвать чистой.
Возвращаемое значение чистых функций будет всегда одинаковым для одного и того же
набора входящих параметров. В этом случае, мы можем не переживать за работоспособность программы в целом, если заменим вызов чистой функции на вычисленное значение. Все математические функции - это чистые функции, в то время как функции работы с датой и rand() - нет.
Функции высших порядков
Если чистые функции можно реализовать практически при любом подходе, функции высшего порядка - это очень характерная отличительная черта функционального программирования. Особенностью функций высших порядков является то, что они могут принимать в качестве аргументов и возвращать другие функции. В PHP - это лямбда функции и замыкания.
Лямбда функции
Лямбда функции (также известные, как анонимные функции) - это ничто иное, как функции без названия. Работа с подобными функциями осуществляется через переменную, которой данная функция была присвоена.
Возможность создания подобных функций есть во множестве языков. Вы наверняка уже писали их в вашем JavaScript коде, когда реализовывали функции обратного действия при работе с ajax.
1 $("#myButton").click(function () {2 // do something3 });Приведённый фрагмент кода - это ничто иное, как создание анонимной функции.
В PHP лямбда функции появились в версии 5.3:
1 <?php
2$square = function ($arg) {
3 return $arg * $arg;
4 };5 6 $value = $square(2); // 4Когда речь идёт об анонимных функциях, очень важно понимать область видимости переменных. К примеру, в JavaScript анонимные функции имеют доступ к переменным за их пределами, а в PHP - нет.
Замыкания
Иногда всё же возникает необходимость иметь доступ к какой-то переменной, которая находится за пределами анонимной функции, но не является входящим параметром. Для того чтобы получить доступ к подобным переменным, можно воспользоваться замыканиями, используя ключевое слово use:
1 <?php2 $rate = .12;3
4$findInterest = function ($value) use ($rate) {
5 return $value * $rate;
6 };7 8 $interest = $findInterest(100);В этом случае, мы не передаём переменную как входящий параметр функции, а получаем к ней доступ, используя use.
Каррирование и частичное применение
Функции частичного применения - это функции содержащие другие функции, которые работают с набором аргументов родителя.
В PHP мы можем создавать подобные функции при помощи замыканий. Ниже вы можете найти пример вычисления объёма коробки. Все аргументы являются необязательными. Однако, если передать меньше 3х параметров, то запустится ещё и другая внутренняя функция.
01 <?php
02$volume = function ($length = 0, $width = 0, $height = 0) use (&$volume) {
03 $args = func_get_args();04 $numArgs = func_num_args();
05 if ($numArgs == 3) {
06 return $length * $width * $height;
07 }
08 else if ($numArgs < 3) {
09 return function() use(&$volume, $args) {10 $newArgs = array_merge($args, func_get_args());11 return call_user_func_array($volume, $newArgs);12 };13 }14 else {
15 throw new BadFunctionCallException("Too many arguments");
16 }17 };В первой проверке мы проверяем количество аргументов. Если оно равно 3, то возвращаем результат. Если изначальное количество аргументов меньше, вызываем другую функцию, которая пытается найти решение с заданными данными.
Таким образом, мы можем вычислить размер коробки, передав сначала один аргумент, а потом и другие.
1 <?php2 $standardVolume = $volume(10);3 4 $vol = $standardVolume(5, 5); // 250Каррирование - это специальный вид функции частичного применения, когда каждый аргумент может быть принят в отдельную функцию. Что-то типа f(x,y,z) to f(x)(y)(z). В PHP такой синтаксис невозможен, но реализовать принцип можно.
Плюсы и минусы
В использовании функционального подхода есть множество плюсов. К примеру, анонимные функции можно использовать в качестве функций обратного вызова. Как в фрэймворке Slim:
1 <?php
2$app = new \Slim\Slim();
3 $app->get("/home", function () {4 // show home page5 });В данном примере, анонимная функция запустится, когда пользователь зайдёт по адресу home.
При функциональном подходе нужно писать функции, которые выполняют какую-то свою узкопрофильную задачу, не затрагивающую какие-то глобальные вещи. Следуя данной парадигме, ваши программы не будут разбухать.
Однако стоит заметить, что не все приёмы данной парадигмы можно реализовать в PHP. В качестве примера, можно привести работу с параллельными процессами.
Также не всегда можно определить сложность рекурсивной функции и её эффект на производительность кода. Иногда стоит отойти от функционального принципа.
Наверное самым большим недостатком функционального подхода является то, что нужно отказаться от императивного мышления. Если это сделать, то новый подход к программированию может даже и увлечь.
Итог
Функциональное программирование - это больше, чем просто подход. Это больше способ мышления, причём вне зависимости от языка.