КОнтакты, предложения, отзывы

.rar или .zip
Вложение
Онлайн-чат
На этом сайте, вы найдёте полезную информацию, практические советы в области веб-программирования, веб-дизайна и веб-разработок в целом. Мы с удовольствием поделимся с вами реальными примерами и решениями задач, связанных с jQuery , JavaScript , PHP и MySQL , версткой сайтов , поможем разобраться новичкам с современными технологиями, такими как Ajax , HTML5 , CSS3 и многими другими.

PHP->Closures

Несмотря на то, что анонимные функции относятся не только к области ООП, они настолько полезны, что я не мог их здесь не упомянуть. Всё дело в том, чтто они активно используются в обьектно-ориентированных приложених наряду с фунуциями обратного вызова. Более того, в этой области за последнее время было сделано несколько довольно интересных открытий
Для начала давайте определим несколько классов.
class Product{
  public $name;
  public $price;
  
  function __construct($name, $price){
    $this->name = $name;
    $this->price = $price;
  }
}

class ProcessSale{
  private $callbacks;
  
  function registerCallback($callback){
    if(!is_callable($callback)){
      throw new Exception("Функция обратного вызова не вызываемая");
    }
    
    $this->callbacks[] = $callback;
  }
  
  function sale(Product $product){
    print "{$product->name}: обрабатывается... <br>";
    foreach($this->callbacks as $callback){
      call_user_func($callback, $product);
    }
  }
}
Этот код предназначен для запуска нескольких функций обратного вызова. В нём определены два класса. В классе Product просто сохраняются значения свойств $name и $price. Для компактности я обьявил их открытыми.
В классе ProcessSale определены два метода. Методу registerCallback() передаётся обычная скалярная переменная без всяких уточнений. После её проверки она добавляется в массив функций обратного вызова $callbacks. Процесс тестирования выполняется с помощью встроенной функции is_callable(). В результате гарантируется, что методу registerCallback() будет передано имя функции, которую можно вызвать.
Методу sale() передаётся обьект типа Product. Метод выводит об этом информацию и затем в цикле выполняет перебор массива $callbacks. Каждый элемент вместе с обьектом типа Product передаётся функции call_user_func(), которая, собственно, и вызывает код, написанный пользователем.
Чем же так полезны функции обратного вызова? Они позволяют в процессе выполнения программы добавлять компоненту новые функциональные возможности. Предусмотрев в обьекте работу с функциями обратного вызова, вы тем самым позволите другим программистам расширять функциональность вашего кода, причём при таких обстоятельствах, о которых раньше вы даже не догадывались. Например, через какое-то время пользователь класса ProcessSale захочет создать журнал продаж и т.п.
Начиная с версии PHP 5.3 существует элегантный способ создания анонимных функций вместо некрасивого синтаксиса create_function(). Теперь мы можем просто обьявить функцию как обычно, а затем присвоить ссылку на неё переменной. И всё это - в одном операторе!
$logger = function(Product $product){
  print " Записываем ({$product->name})<br>";
};

$processor = new ProcessSale;
$processor->registerCallback($logger);

$processor->sale(new Product("Чай", 20));
$processor->sale(new Product("Кофе", 50));

// вывод::
Чай: обрабатывается... 
Записываем (Чай)
Кофе: обрабатывается... 
Записываем (Кофе)
Обратите внимание на то, что поскольку в операторе присвоения используется встроенная функция, то в конце блока нужно обязательно поставить точку с запятой.

Само собой разумеется, что функции обратного вызова не обязательно должны быть анонимными.
class Mailer{
  
  private $myemail = 'superAdmin@ggmail.cum';
  
  function mailSale(Product $product){
    mail($myemail, 'Saled!', $product->name);
  }
  
  static function mailSaleExpensive(Product $product){
    mail($myemail, 'Saled дорогой товар!', $product->name);
  }
}

$processor = new ProcessSale;
$processor->registerCallback(array(new Mailer, 'mailSale'));

$processor->sale(new Product("Чай", 20));
$processor->sale(new Product("Кофе", 50));
При вызове метода registerCallback() я передал ему в качестве параметра массив. Первым элементом этого массива является обьект типа Mailer, а вторым - строка, содержащая имя метода, который мы хотим вызвать. Помните, что в методе registerCallback() с помощью ф-ции is_callable() выполняется проверка аргумента на предмет того, можно ли его вызвать? Данная функция достаточно интеллектуальна и распознаёт массивы подобного рода.
В случае если функция статическая, передается имя класса и имя метода.

Разумеется, что анонимную функцию можно вернуть из метода, как показано ниже:
class Totaliser{
  static function warnAmount(){
    return function (Product $product){
      if($product->price > 25){
        echo "Покупается дорогой товар {$product->name}<br>";
        Mailer::mailSaleExpensive($product);
      }
    };
  }
}

$processor = new ProcessSale;
$processor->registerCallback(Totaliser::warnAmount());
В этом примере нет ничего интересного, кроме того, что метод warnAmount используется в качестве фабрики анонимной функции. Тем не менее подобная структура позволяет мне делать гораздо большее, чем просто генерировать анонимную функцию. Она позволяет мне воспользоваться преимуществами механизма замыкания (Closures). В анонимной функции нового типа могут использоваться переменные, обьявленные в другой анонимной функции, находящейся в родительской области видимости.
Чтобы анонимная функция могла воспользоваться переменными, определёнными в родительской области видимости, используется ключевое слово use, как показано в примере ниже:
class Totaliser{
  static function warnAmount($amt){
    $count = 0;
    return function (Product $product) use ($amt, &$count){
      $count += $product->price;
      print "Сумма:: $count <br>";
      
      if($count > $amt){
        echo "Продано товаров на сумму {$count}<br>";
        //Mailer::mailSaleExpensive($product);
      }
    };
  }
}

$processor = new ProcessSale;
$processor->registerCallback(Totaliser::warnAmount(35));

$processor->sale(new Product("Чай", 20));
$processor->sale(new Product("Кофе", 50));
В директиве use анонимной функции, которая возвращается методом Totaliser::warnAmount() указаны две переменные. Первая из них - это $amt, которая является аргументом, переданным методу warnAmount. Вторая - замкнутая переменная $count. Она обьявлена в теле метода и начальное её состояние равно нулю. Обратите внимание на то, что перед именем переменной стоит символ амперсанда &, указывающий на то, что данная переменная будет передаваться по ссылке. Дело в том, что в теле анонимной функции я добавляю к ней цену товара и затем сравниваю новую сумму со значением $amt. Если будет достигнуто пороговое значение, выводится сообщение.
Значение переменной $count сохраняется между вызовами функции обратного вызова. Обе переменные, $amt и $count остаются связанными с этой функцией, поскольку они указаны в крнтеусте её обьявления и перечислены в директиве use.
2015.08.26 51

Приходит программист к окулисту. Тот его усаживает напротив таблицы, берет указку: - Читайте! - "БHОПHЯ"... Доктор, у вас что-то не то с кодировкой!
Войдите или Зарегистрируйтесь чтобы оставить комментарий

Комментарии


    Яндекс.Метрика Яндекс.Метрика