четверг, 24 июля 2014 г.

Функции в PHP.

Функции в PHP.

Смысл и назначение.

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


1. Функции выполняют роль системных или пользовательских подпрограмм, т.е. автономных алгоритмов, которые можно вызвать из любого места основного кода.

2. Функции, заключая в себе некий обобщенный блок логики, улучшют читабельность и архитектуру кода. Т.к. отпадает необходимость вставлять этот блок в места необходимого применения, повторяя одинаковые участки и увеличивая (иногда многократно) сплошное полотно кода.

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

Синтаксис.

Объявление. Функция объявляется ключевым словом "function". Затем следует имя функции. после имени - круглые скобки (с перечислением параметров), в виде переменных через запятую. Если параметров нет, скобки остаются пустыми. После круглых скобок следут блок с кодом функции в {фигурных кавычках}.
К примеру, классический helloworld, выводимый с помощью функции, выглядит так:

<?php
 
  function hello(){
    echo "Hello, world!";
  }


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

<?php
 
  function hello(){
    $result = "Hello, world!";
    return $result;
  }


Вызов функции осуществляется указанием её имени с последующими круглыми скобками.

<?php
 
  function hello(){
    $result = "Hello, world!";
    return $result;
  }
 
  print hello(); // выведет: Hello, world!



Параметры функций.

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

<?php
 
function hello($somebody){
  $result = "Hello, $somebody";
  return $result;
}

print hello("Kitty"); // : Hello, Kitty!

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

<?php
 
function hello(& $somebody){
  $result = "Hello, $somebody";
  return $result;
}

print hello("Kitty"); // : Hello, Kitty!


Параметры по умолчанию.

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

<?php
 
function hello($somebody = "world"){
  $result = "Hello, $somebody";
  return $result;
}

print hello("Kitty"); // : Hello, Kitty!
print hello();  // Hello, world!


Статические переменные в функциях.

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

<?php
 function foo(){
    static $x = 0;
    $x++;
    print " x = $x \n";
 }
 
 for($i=0; $i<10; ++$i){
    foo();
 }



Результат работы кода:

x = 1 ; x = 2 ; x = 3 ; x = 4 ; x = 5 ; x = 6 ; x = 7 ; x = 8 ; x = 9 ; x = 10 ;


Лямбда-функции.

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

<?php

 $sum = function($a, $b){
    return $a + $b;
 };
 
 print $sum (100, 200); // out = 300


Как и в классических функциональных языках, лямбда-функции могут замыкать на себя родительский контекст, откуда и название "замыкания".
Замыкание анонимной функции на локальный контекст, в котором она была объявлена, совершается при помощи ключевого слова "use". Переменные, перечисленные в круглых скобках после "use" становятся доступны внутри анонимной функции и после выхода за пределы родительского пространства имен. Например, в случае возвращения анонимной функции как результата работы родительской функции. Ниже - пример возвращаемой анонимной функции, которая при дальнейшем вызове использует для сравнения длину массива, сохраненную в переменной $num.

<?php

 function foo($arg){
    $num = count($arg);
    return function ($array) use ($num) {
        $arrayNum = count($array);
        if ($num === $arrayNum)
            return "EQUAL\n";
        return (($arrayNum > $num) ? "MORE" : "LESS") . "\n";
    };
 }
 
 $data = array(1, 2, 3, 4, 5);
 $bar = foo($data);
 
 print $bar(array(1,2,3));
 print $bar(array(1,2,3,4,5,6,7));
 print $bar(array(1,2,3,4,50));


Результат:
LESS
MORE
EQUAL


Стандартные (встроенные) функции PHP.

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

Функции для работы с функциями.

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

call_user_func
<?php
    // функция, которая вызывает переданную ей функцию
    call_user_func (
        function($arg1, $arg2){
            print "Print user name: $arg1, $arg2.";
        }, 
        'Vasya', 'Pupkin'
    );


function_exists
<?php
    // определяет определена ли указанная функция 
    function foo(){
        print 'foo fun';
    }
    
    function print_exists($name){
        if(function_exists($name)){
            print "function $name exists \n";
        } else {
            print "function $name didn't defined \n";
        }
    }

    print_exists('foo');
    print_exists('foo2');



Функции с переменным количеством параметров.

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

<?php
    //...
    function foo(){
        $args = func_get_args();
        foreach($args as $i => $argument){
            print "argument[$i] = $argument \n";
        }
    }
    
    foo('Vasya', 'manager', 'Pupkina str.', 25);
Результат:
argument[0] = Vasya 
argument[1] = manager 
argument[2] = Pupkina str. 
argument[3] = 25 


Как мы видим, функции - мощный и удобный инструмент для структурирования и оптимизации кода. Следующий этап на этом пути - классы и объектно-ориентированное программирование.

PS. Бонус для дотошного читателя :)
Возник вопрос о сроке жизни контекста, окружающего лямбда-функцию.
И можно ли привязать несколько функций на один контекст.
При некотором рассмотрении выясняется нюанс, очевидный не сразу.
Во-первых, мы не можем просто так вернуть несколько методов, т.к. возвращается-то один результат.
Во-вторых, в каждый вызов функции, порождающей лямбду, создается новый контекст, переменные которого и становятся доступны анонимной функции.
В итоге получилось вот такое решение, больше похожее на некий странный ООП. Странный в традициях PHP, но вполне имеющий место в JavaScript, например.
Вот это решение.
<?php
    function foo(){
        $str = "ABC ";
        $x = new StdClass();
        $x->f1 = function() use (&$str){
                    static $count = 1;
                    print ($str .= "Q" . $count++ . " ") . "\n";
                };
        $x->f2 = function() use (&$str){
                    static $count = 1;
                    print ($str .= "T" . $count++ . " ") . "\n";
                };
        $x->f3 = function () use (&$str){
                return $str;
            };
        return $x;
    }
    
    $t = foo();
    $f1 = $t->f1;
    $f2 = $t->f2;
    $f3 = $t->f3;
    $f1(); $f2(); $f1(); $f2();
    print "\nResult: " .  $f3();
Результат:
ABC Q1 
ABC Q1 T1 
ABC Q1 T1 Q2 
ABC Q1 T1 Q2 T2 

Result: ABC Q1 T1 Q2 T2 

PPS. По некотором размышлении пришла мысль, что в ходе чтения статей неподготовленным кодером использование StdClass в последнем примере может оказаться непонятным. Посему пример имеет альтернативную реализацию, см. ниже. Результат выполнения тот же.
Не-объектная реализация мульти-лямбдового контекста.
<?php
    function foo(){
        $str = "ABC ";
        $x = array();
        $x['f1'] = function() use (&$str){
                    static $count = 1;
                    print ($str .= "Q" . $count++ . " ") . "\n";
                };
        $x['f2'] = function() use (&$str){
                    static $count = 1;
                    print ($str .= "T" . $count++ . " ") . "\n";
                };
        $x['f3'] = function () use (&$str){
                return $str;
            };
        return $x;
    }
    
    $t = foo();  // получаем ссылку на массив
    $f1 = $t['f1'];  // предаем ссылку на функцию в переменную
    $f2 = $t['f2'];
    $f3 = $t['f3'];
    // вызываем функции с общим контекстом объявления
    $t['f1'](); $t['f2'](); // по ссылке в массиве
    $f1(); $f2(); // по ссылке в переменных
    // вывод итогового результата
    print "\nResult: " .  $f3();
Ну и немного комментариев, на всякий случай :)


Комментариев нет:

Отправить комментарий