Explication détaillée de l'utilisation de la fermeture en php

墨辰丷
Libérer: 2023-03-27 09:32:01
original
1270 Les gens l'ont consulté

Cet article présente principalement l'explication détaillée de l'utilisation de la fermeture en php. Les amis qui en ont besoin peuvent s'y référer

Cet article présente principalement l'explication détaillée de l'utilisation de la fermeture en php. il peut s'y référer

Les fonctions de fermeture, anonymes, ont été introduites dans php5.3, également connues sous le nom de fonctions anonymes. Le sens littéral est une fonction sans nom défini. Par exemple, le code suivant (le nom du fichier est do.php)

<?php
function A() {
  return 100;
};
function B(Closure $callback)
{
  return $callback();
}
$a = B(A());
print_r($a);//输出:Fatal error: Uncaught TypeError: Argument 1 passed to B() must be an instance of Closure, integer given, called in D:\web\test\do.php on line 11 and defined in D:\web\test\do.php:6 Stack trace: #0 D:\web\test\do.php(11): B(100) #1 {main} thrown in D:\web\test\do.php on line 6
?>
Copier après la connexion

A() ici ne peut jamais être utilisé comme paramètre de B, car A Ce n'est pas une fonction "anonyme".

Il devrait donc être modifié comme suit :

<?php
$f = function () {
  return 100;
};
function B(Closure $callback)
{
  return $callback();
}
$a = B($f);
print_r($a);//输出100
<?
$func = function( $param ) {
  echo $param;
};
$func( &#39;hello word&#39; );
//输出:hello word
Copier après la connexion

Mettre en œuvre la fermeture

Passez des fonctions anonymes comme paramètres dans des fonctions ordinaires, et elles peuvent également être renvoyées. Cela implémente une fermeture simple.

Je vais vous donner trois exemples ci-dessous :

<?php
//例一
//在函数里定义一个匿名函数,并且调用它
function printStr() {
  $func = function( $str ) {
    echo $str;
  };
  $func( &#39; hello my girlfriend ! &#39; );
}
printStr();//输出 hello my girlfriend !
//例二
//在函数中把匿名函数返回,并且调用它
function getPrintStrFunc() {
  $func = function( $str ) {
    echo $str;
  };
  return $func;
}
$printStrFunc = getPrintStrFunc();
$printStrFunc( &#39; do you love me ? &#39; );//输出 do you love me ?
//例三
//把匿名函数当做参数传递,并且调用它
function callFunc( $func ) {
  $func( &#39; no!i hate you &#39; );
}
$printStrFunc = function( $str ) {
  echo $str.&#39;<br>&#39;;
};
callFunc( $printStrFunc );
//也可以直接将匿名函数进行传递。如果你了解js,这种写法可能会很熟悉
callFunc( function( $str ) {
  echo $str; //输出no!i hate you
} );
Copier après la connexion

Mots clés reliant les fermetures et les variables externes : UTILISER

Fermetures peut enregistrer certaines variables et valeurs​​dans le contexte du bloc de code. Par défaut en PHP, les fonctions anonymes ne peuvent pas appeler de variables de contexte dans le bloc de code où elles se trouvent, mais doivent utiliser le mot-clé use.

Regardons un autre exemple (ok, je manque d'argent, je suis vulgaire) :

<?php
function getMoney() {
  $rmb = 1;
  $dollar = 8;
  $func = function() use ( $rmb ) {
    echo $rmb;
    echo $dollar;
  };
  $func();
}
getMoney();
//输出:1
Copier après la connexion

Comme tu peut voir, dollar S'il n'est pas déclaré dans le mot-clé use, il ne peut pas être obtenu dans cette fonction anonyme, alors faites attention à ce problème pendant le développement.

Certaines personnes peuvent se demander s'il est possible de modifier les variables de contexte dans les fonctions anonymes, mais j'ai trouvé que cela ne semble pas possible :

<?php
function getMoney() {
  $rmb = 1;
  $func = function() use ( $rmb ) {
    echo $rmb.&#39;<br>&#39;;
    //把$rmb的值加1
    $rmb++;
  };
  $func();
  echo $rmb;
}
getMoney();
//输出:
//1
//1
Copier après la connexion

Eh bien, il s'avère que ce à quoi use fait référence n'est qu'un clone de la variable. Mais que se passe-t-il si je souhaite citer complètement la variable au lieu de la copier ? Pour obtenir cet effet, ajoutez simplement un symbole & avant la variable :

<?php
function getMoney() {
  $rmb = 1;
  $func = function() use ( &$rmb ) {
    echo $rmb.&#39;<br>&#39;;
    //把$rmb的值加1
    $rmb++;
  };
  $func();
  echo $rmb;
}
getMoney();
//输出:
//1
//2
Copier après la connexion

D'accord, la fonction anonyme peut donc référencer les variables contextuelles. Si la fonction anonyme est renvoyée au monde extérieur, la fonction anonyme sauvegardera les variables référencées par l'utilisation, mais le monde extérieur ne pourra pas obtenir ces variables. De cette façon, le concept de « fermeture » peut être plus clair.

Selon la description, changeons l'exemple ci-dessus :

<?php
function getMoneyFunc() {
  $rmb = 1;
  $func = function() use ( &$rmb ) {
    echo $rmb.&#39;<br>&#39;;
    //把$rmb的值加1
    $rmb++;
  };
  return $func;
}
$getMoney = getMoneyFunc();
$getMoney();
$getMoney();
$getMoney();
//输出:
//1
//2
//3
Copier après la connexion

D'accord, tellement, alors si nous voulons appeler Quoi à propos des fonctions anonymes à l'intérieur d'une classe ? Accédez directement à la démo

<?php
class A {
  public static function testA() {
    return function($i) { //返回匿名函数
      return $i+100;
    };
  }
}
function B(Closure $callback)
{
  return $callback(200);
}
$a = B(A::testA());
print_r($a);//输出 300
Copier après la connexion

où A::testA() renvoie une fonction sans nom.

Le concept de liaison

La fermeture dans l'exemple ci-dessus est juste une fonction anonyme globale. D'accord, nous voulons maintenant spécifier une classe. Il existe une fonction anonyme. On comprend également que la portée d'accès de cette fonction anonyme n'est plus globale, mais la portée d'accès d'une classe.

Ensuite, nous devons lier "une fonction anonyme à une classe".

<?php
class A {
  public $base = 100;
}
class B {
  private $base = 1000;
}
$f = function () {
  return $this->base + 3;
};
$a = Closure::bind($f, new A);
print_r($a());//输出 103
echo PHP_EOL;
$b = Closure::bind($f, new B , &#39;B&#39;);
print_r($b());//输出1003
Copier après la connexion

Dans l'exemple ci-dessus, il y a un this inexplicable dans la fonction anonyme f. Ce mot-clé signifie que cette fonction anonyme doit être déterminée. dans la catégorie.

Après la liaison, c'est comme s'il existait une telle fonction dans A, mais que cette fonction soit publique ou privée, le dernier paramètre de bind indique la portée appelable de cette fonction.

Vous avez vu bindTo ci-dessus, jetons un coup d'œil à l'introduction sur le site officiel

(PHP 5 >= 5.4.0, PHP 7)
Copier après la connexion

Closure::bind — Copier une fermeture et la lier Spécifiez l'objet $this spécifié et la portée de la classe.

Explication

public static Closure Closure::bind ( Closure $closure , object $newthis [, Mixed $newscope = 'static' ] )
Cette méthode est Closure::bindTo( ) version statique. Consultez sa documentation pour plus d’informations.

Paramètres

fermeture

Une fonction anonyme qui doit être liée.

newthis

nécessite un objet lié à une fonction anonyme, ou NULL crée une fermeture indépendante.

newscope

La portée de classe que vous souhaitez lier à la fermeture, ou « statique » signifie aucun changement. Si un objet est transmis, le nom de type de l'objet est utilisé. La portée de la classe est utilisée pour déterminer la visibilité des méthodes privées et protégées de l'objet $this dans la fermeture. (Remarque : vous pouvez transmettre le nom de la classe ou une instance de la classe. La valeur par défaut est « statique », ce qui signifie aucun changement.)

Valeur de retour :

Renvoyer une nouvelle fermeture objet ou en cas d'échec Retour FAUX

<?php
class A {
  private static $sfoo = 1;
  private $ifoo = 2;
}
$cl1 = static function() {
  return A::$sfoo;
};
$cl2 = function() {
  return $this->ifoo;
};
$bcl1 = Closure::bind($cl1, null, &#39;A&#39;);
$bcl2 = Closure::bind($cl2, new A(), &#39;A&#39;);
echo $bcl1(), "\n";//输出 1
echo $bcl2(), "\n";//输出 2
Copier après la connexion

Regardons un exemple pour approfondir notre compréhension :

<?php
class A {
  public $base = 100;
}
class B {
  private $base = 1000;
}
class C {
  private static $base = 10000;
}
$f = function () {
  return $this->base + 3;
};
$sf = static function() {
  return self::$base + 3;
};
$a = Closure::bind($f, new A);
print_r($a());//这里输出103,绑定到A类
echo PHP_EOL;
$b = Closure::bind($f, new B , &#39;B&#39;);
print_r($b());//这里输出1003,绑定到B类
echo PHP_EOL;
$c = $sf->bindTo(null, &#39;C&#39;); //注意这里:使用变量#sf绑定到C类,默认第一个参数为null
print_r($c());//这里输出10003
Copier après la connexion

Regardons une autre démo :

<?php
/**
 * 复制一个闭包,绑定指定的$this对象和类作用域。
 *
 * @author fantasy
 */
class Animal {
  private static $cat = "加菲猫";
  private $dog = "汪汪队";
  public $pig = "猪猪侠";
}
/*
 * 获取Animal类静态私有成员属性
 */
$cat = static function() {
  return Animal::$cat;
};
/*
 * 获取Animal实例私有成员属性
 */
$dog = function() {
  return $this->dog;
};
/*
 * 获取Animal实例公有成员属性
 */
$pig = function() {
  return $this->pig;
};
$bindCat = Closure::bind($cat, null, new Animal());// 给闭包绑定了Animal实例的作用域,但未给闭包绑定$this对象
$bindDog = Closure::bind($dog, new Animal(), &#39;Animal&#39;);// 给闭包绑定了Animal类的作用域,同时将Animal实例对象作为$this对象绑定给闭包
$bindPig = Closure::bind($pig, new Animal());// 将Animal实例对象作为$this对象绑定给闭包,保留闭包原有作用域
echo $bindCat(),&#39;<br>&#39;;// 输出:加菲猫,根据绑定规则,允许闭包通过作用域限定操作符获取Animal类静态私有成员属性
echo $bindDog(),&#39;<br>&#39;;// 输出:汪汪队, 根据绑定规则,允许闭包通过绑定的$this对象(Animal实例对象)获取Animal实例私有成员属性
echo $bindPig(),&#39;<br>&#39;;// 输出:猪猪侠, 根据绑定规则,允许闭包通过绑定的$this对象获取Animal实例公有成员属性
Copier après la connexion

À travers les exemples ci-dessus, il n'est en fait pas difficile de comprendre la reliure anonyme. .. .Nous envisageons une démo étendue (présentant les fonctionnalités des traits)

<?php
/**
 * 给类动态添加新方法
 *
 * @author fantasy
 */
trait DynamicTrait {
  /**
   * 自动调用类中存在的方法
   */
  public function __call($name, $args) {
    if(is_callable($this->$name)){
      return call_user_func($this->$name, $args);
    }else{
      throw new \RuntimeException("Method {$name} does not exist");
    }
  }
  /**
   * 添加方法
   */
  public function __set($name, $value) {
    $this->$name = is_callable($value)?
      $value->bindTo($this, $this):
      $value;
  }
}
/**
 * 只带属性不带方法动物类
 *
 * @author fantasy
 */
class Animal {
  use DynamicTrait;
  private $dog = &#39;汪汪队&#39;;
}
$animal = new Animal;
// 往动物类实例中添加一个方法获取实例的私有属性$dog
$animal->getdog = function() {
  return $this->dog;
};
echo $animal->getdog();//输出 汪汪队
Copier après la connexion

Par exemple, nous utilisons maintenant l'environnement d'achat actuel

<?php
/**
 * 一个基本的购物车,包括一些已经添加的商品和每种商品的数量
 *
 * @author fantasy
 */
class Cart {
  // 定义商品价格
  const PRICE_BUTTER = 10.00;
  const PRICE_MILK  = 30.33;
  const PRICE_EGGS  = 80.88; 
  protected  $products = array();
  /**
   * 添加商品和数量
   *
   * @access public
   * @param string 商品名称
   * @param string 商品数量
   */
  public function add($item, $quantity) {
    $this->products[$item] = $quantity;
  }
  /**
   * 获取单项商品数量
   *
   * @access public
   * @param string 商品名称
   */
  public function getQuantity($item) {
    return isset($this->products[$item]) ? $this->products[$item] : FALSE;
  }
  /**
   * 获取总价
   *
   * @access public
   * @param string 税率
   */
  public function getTotal($tax) {
    $total = 0.00;
    $callback = function ($quantity, $item) use ($tax, &$total) {
      $pricePerItem = constant(__CLASS__ . "::PRICE_" . strtoupper($item)); //调用以上对应的常量
      $total += ($pricePerItem * $quantity) * ($tax + 1.0);
    };
    array_walk($this->products, $callback);
    return round($total, 2);
  }
}
$my_cart = new Cart;
// 往购物车里添加商品及对应数量
$my_cart->add(&#39;butter&#39;, 10);
$my_cart->add(&#39;milk&#39;, 3);
$my_cart->add(&#39;eggs&#39;, 12);
// 打出出总价格,其中有 3% 的销售税.
echo $my_cart->getTotal(0.03);//输出 1196.4
Copier après la connexion

Remarque supplémentaire : les fermetures peuvent utiliser la touche USE pour connecter des variables externes.

Recommandations associées :

Utilisation de fonctions anonymes et de fermetures (closure) en php

Présentation des exemples d'utilisation de closure en php

Explication détaillée de la classe Closure en PHP

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!