Внутренние функции и замыкания Closure в PHP ч.2

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

В случае PHP и внутренних функций логика все еще работает, но это приводит к поведению, которого вы не ожидаете.

Рассмотрим внутреннюю функцию, определенную в методе класса.

class MyClass
{
 public $MyProperty;
 public function MyMethod()
 {
  if(!function_exists("MyInnerFunction")){
   function MyInnerFunction()
   {
    echo('MyInnerFunction ');
   }
  }
 }
}

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

$MyObject->MyInnerMethod();

Чтобы создать глобальную функцию, вы должны вызвать метод, а затем функцию, которую он создал:

$MyObject = new MyClass;
$MyObject->MyMethod();
MyInnerFunction();

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

Например, внутренняя функция не имеет доступа к $this — она ​​просто не является частью класса. Если вы пытаетесь:

class MyClass
{
 public $MyProperty="Default Value";
 public function MyMethod()
 {
  echo($this->MyProperty);
  if(!function_exists("MyInnerFunction")){
   function MyInnerFunction()
   {
    echo($this->MyProperty);
    echo('MyInnerFunction ');
   }
  }
 }
}

Вы обнаружите, что внутренняя функция генерирует ошибку

Using $this when not in object context

Стандартное решение для такого рода проблем заключается в создании новой переменной — обычно называемой $that — и явной передаче в $this ссылке:

function MyInnerFunction($that)
{
 echo($that->MyProperty);
 echo('MyInnerFunction ');
}

и организовать вызов MyInnerFunction как:

MyInnerFunction($this);

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

Использование внутренних функций
В этот момент вы понимаете внутренние функции, но вполне можете поинтересоваться, какое у них применение.

Ответ заключается в том, что многие фреймворки разработки — например, Joomla — делят задачу создания расширений или просто использования фреймворка на методы написания.

Поэтому в документации часто говорится — создайте некоторый код в файле с именем template.php и поместите его в определенный каталог. В этом случае платформа включает файл в определение класса. Например:

class HTMLview {
 public function htmlview(){
  include "template.php"
 }
}

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

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

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

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

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

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

«Я должен повторить этот код, потому что я не могу определить функцию»

Ну, вы можете определить функцию, чтобы избежать повторения кода, если вы следуете некоторым простым правилам. Правила таковы:

1. определите функцию условно, как показано выше, чтобы убедиться, что она создается только один раз.
2. определите любые функции, которые вы хотите использовать в начале файла, чтобы их можно было вызывать из остальной части кода.
3. вы не можете использовать $this, но вы можете определить переменную $that и передать ее в вашу функцию
4. вы все еще не можете получить доступ к защищенным или закрытым членам, используя $that
В некоторых случаях ограничение только на использование публичных элементов является проблемой, но обычно это не так. Точно так же, если вы также знаете, что метод будет выполняться только один раз, вы также можете удалить условное объявление и просто определить функцию обычным способом.

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

Вкратце — вы можете использовать внутренние функции, чтобы разделить метод, который вы пишете, как часть включаемого файла, даже если файл включен в другую функцию или в метод.

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

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

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

То есть для определения анонимной функции вы пишете что-то вроде:

$variable = function(parameters){
    function body
};

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

Например:

$MyFunction1 = function() {
 echo('MyFunction');
};

$MyFunction2 = $MyFunction1;

$MyFunction1();
$MyFunction2();

Обратите внимание, что вы можете использовать ссылку на анонимную функцию так же, как если бы она была переменной, содержащей значение. В этом случае мы храним другую ссылку на анонимную функцию в MyFunction2. Теперь вы можете вызывать функцию, используя любую переменную — функция не имеет фиксированного «имени».

Это означает, что теперь внутренняя анонимная функция, хранящаяся в локальной переменной, действительно является локальной.

Например

function MyFunction(){
 echo("My Function");
 $MyInnerFunction = function()
 {
   echo('MyInnerFunction');
 };
}

Это определяет внутреннюю анонимную функцию, и вы можете вызвать функцию, используя переменную как:

$MyInnerFunction();

Обратите внимание, что поскольку переменная является локальной, вы не можете вызывать функцию из любого другого контекста, кроме внешней функции. Также, как только MyFunction завершает работу, локальная переменная уничтожается и внутренняя анонимная функция фактически больше не существует.

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

Внутренние функции и замыкания Closure в PHP ч. 3

Переведено с ресурса: i-programmer.info/programming/php/1130-php-inner-functions-and-closure.html

Добавить комментарий