深圳全飞鸿

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 401|回复: 1
打印 上一主题 下一主题

PHP 匿名函数 function use 与直接传参的区别

[复制链接]

800

主题

1379

帖子

7724

积分

版主

Rank: 7Rank: 7Rank: 7

积分
7724
跳转到指定楼层
楼主
发表于 2022-2-27 15:03:51 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
以下是PHP示例代码:
  1. <?php
  2. $message = 'hello';

  3. // 没有 "use"
  4. $example = function () {
  5.     var_dump($message);
  6. };
  7. echo $example();
  8. ?>
复制代码
结果:
Notice: Undefined variable: message in /example.php on line 6
NULL

  1. <?php
  2. $message = 'hello';

  3. // 继承 $message
  4. $example = function () use ($message) {
  5.     var_dump($message);
  6. };
  7. echo $example();
复制代码
结果:
string(5) "hello"

  1. <?php
  2. $message = 'hello';

  3. // 继承 $message
  4. $example = function () use ($message) {
  5.     var_dump($message);
  6. };
  7. // Inherited variable's value is from when the function
  8. // is defined, not when called
  9. $message = 'world';
  10. echo $example();
复制代码
结果:
string(5) "hello"

  1. // Reset message
  2. $message = 'hello';

  3. // Inherit by-reference
  4. $example = function () use (&$message) {
  5.     var_dump($message);
  6. };
  7. echo $example();
复制代码
结果:
string(5) "hello"

  1. // The changed value in the parent scope
  2. // is reflected inside the function call
  3. $message = 'world';
  4. echo $example();

  5. // Closures can also accept regular arguments
  6. $example = function ($arg) use ($message) {
  7.     var_dump($arg . ' ' . $message);
  8. };
  9. $example("hello");
复制代码
结果:
string(5) "world"
string(11) "hello world"


在第三个echo的时候,程序先改变了$message的值,但是输出仍然为 "hello",而非"word"。
由此可见use的参数继承的值是在匿名函数创建的时候就不会再更改了。除非在参数前加 & ,但这样的话跟直接传参没有多大的区别,那么use也没有意义了。

回复

使用道具 举报

800

主题

1379

帖子

7724

积分

版主

Rank: 7Rank: 7Rank: 7

积分
7724
沙发
 楼主| 发表于 2022-2-27 18:51:43 | 只看该作者
PHP闭包 function() use(){}作用

php的闭包(Closure)也就是匿名函数。是PHP5.3引入的。

闭包的语法很简单,需要注意的关键字就只有use,use意思是连接闭包和外界变量。

$a =function()use($b) {
}
闭包的几个作用:

1.减少foreach的循环的代码
  1. <?php

  2. // 一个基本的购物车,包括一些已经添加的商品和每种商品的数量。
  3. // 其中有一个方法用来计算购物车中所有商品的总价格。该方法使用了一个closure作为回调函数。
  4. class Cart {
  5.     const PRICE_BUTTER = 1.00;
  6.     const PRICE_MILK   = 3.00;
  7.     const PRICE_EGGS   = 6.95;

  8.     protected $products = [];

  9.     public function add($product, $quantity) {
  10.         $this->products[$product] = $quantity;
  11.     }

  12.     public function getQuantity($product) {
  13.         return isset($this->products[$product]) ? $this->products[$product] : FALSE;
  14.     }

  15.     public function getTotal($tax) {
  16.         $total = 0.00;

  17.         $callback =
  18.         function ($quantity, $product) use ($tax, &$total) {
  19.             $pricePerItem = constant(__CLASS__ . "::PRICE_" .
  20.                 strtoupper($product));
  21.             $total += ($pricePerItem * $quantity) * ($tax + 1.0);
  22.         };

  23.         array_walk($this->products, $callback);
  24.         return round($total, 2);
  25.     }
  26. }

  27. $my_cart = new Cart;

  28. // 往购物车里添加条目
  29. $my_cart->add('butter', 1);
  30. $my_cart->add('milk', 3);
  31. $my_cart->add('eggs', 6);

  32. // 打出出总价格,其中有 5% 的销售税.
  33. print $my_cart->getTotal(0.05) . "\n";
  34. // The result is 54.29
  35. ?>
复制代码
这里如果我们改造getTotal函数必然要使用到foreach


2.减少函数的参数
  1. <?php

  2. function html($code, $id = "", $class = "") {

  3.     if ($id !== "") {
  4.         $id = " id = \"$id\"";
  5.     }

  6.     $class = ($class !== "") ? " class =\"$class\"" : ">";

  7.     $open = "<$code$id$class>";

  8.     $close = "</$code>";

  9.     return function ($inner = "") use ($open, $close) {

  10.         return "$open$inner$close";};

  11. }

  12. $f=html("code","id","class");
  13. echo $f("hello syant!");
复制代码


如果是使用平时的方法,我们会把inner放到html函数参数中,这样不管是代码阅读还是使用都不如使用闭包

3、解除递归函数
  1. <?php

  2. $fib = function ($n) use (&$fib) {
  3.     if ($n == 0 || $n == 1) {
  4.         return 1;
  5.     }

  6.     return $fib($n - 1) + $fib($n - 2);
  7. };

  8. echo $fib(2) . "\n"; // 2
  9. $lie = $fib;
  10. $fib = function () {die('error');}; //rewrite $fib variable
  11. echo $lie(5); // error because $fib is referenced by closure

  12. ?>
复制代码
注意上题中的use使用了&,这里不使用&会出现错误fib(fib(n-1)是找不到function的(前面没有定义fib的类型)
所以想使用闭包解除循环函数的时候就需要使用
  1. <?php
  2. $recursive = function () use (&$recursive) {
  3. // The function is now available as $recursive
  4. }
  5. ?>
复制代码



关于延迟绑定
如果你需要延迟绑定use里面的变量,你就需要使用引用(&),否则在定义的时候就会做一份拷贝放到use中 //理解use(&$var)
  1. <?php

  2. $result = 0;

  3. $one = function () {var_dump($result);};

  4. $two = function () use ($result) {var_dump($result);};

  5. $three = function () use (&$result) {var_dump($result);};

  6. $result++;

  7. $one(); // outputs NULL: $result is not in scope
  8. $two(); // outputs int(0): $result was copied
  9. $three(); // outputs int(1)
复制代码
使用引用和不使用引用就代表了是调用时赋值,还是申明时候赋值


回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|nagomes  

GMT+8, 2025-6-28 16:36 , Processed in 0.054395 second(s), 20 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表