回调函数和闭包(匿名函数)以及闭包的序列化

2022-04-11  本文已影响0人  PENG先森_晓宇

回调函数

回调函数:Callback (即call then back 被主函数调用运算后会返回主函数),是指通过函数参数传递到其它代码的,某一块可执行代码的引用。

回调函数其实就是callback类型,在方法中可以使用callable关键字来申明形参是回调函数;在方法体内可以使用is_callable($entry)方法来判断是否可回调。

 public function with(callable $entry){
  if(is_callable($entry)){
           //TODO
       }else{
           throw new Exception('参数entry不是回调函数')
       }
  }

到底怎么使用回调函数呢?其实很多例子

  1. 例如我们最常用的array_filter(),可以看到第二个参数就是一个函数,也就是第二个参数其实就是一个回调函数。
$number=[1,2,'a'];
$filter=array_filter($number,function ($value){
    if(is_numeric($value)){
        return true;
    }else{
        return false;
    }
});
  1. 比如我们需要执行mysql的事务,我们通常的做法是,如下:
class mysql
{
    public function init()
    {
       try{
           $con=new Con();
            $con->startTrasnaction();
            //TODO

            $con->commit();
        }catch (\Exception $e){
            $con->rollBack();
        }
    }
}
$a = new mysql();
$a->init();

缺点就是:每次都需要重复写一些new Con(),startTrasnaction(),commit(),rollBack()的代码,所以这里我就可以使用回调函数的方式来轻松降低代码的重复复,如下:

class mysql
{
    public function init()
    {
        $a=$this->a;
        $b=$this->b;
        $con = new SrmCon();//con类的子类
        self::transaction(function ()use ($con){
            //TODO 

        },$con);
    }

    public static function transaction(callable $func,Con $con)
    {
       if(is_callable($func)){
           try{
               $con->startTrasnaction();
               //call_user_func_array()
               call_user_func($func);//调用回调函数
               $con->commit();
           }catch (\Exception $e){
               $con->rollBack();
           }
       }else{
           throw new Exception('参数不是回调函数');
       }
    }
}
////回调函数
$a = new mysql();
$a->init();

通过封装了transaction()方法,在执行一些事务操作时再也不需要写startTrasnaction、commit、rollBack这些了。

transaction这个方法的封装,有俩大特点需要注意下:

闭包(匿名函数)

PHP将匿名函数和闭包视作相同的概念,下面统称闭包,顾名思义就是没有名字的函数。

闭包的定义

匿名函数通常用在回调函数中,同时匿名函数也可以赋值给一个变量后使用,还能像其他任何 PHP 对象那样传递,不过匿名函数仍然是函数,因此可以调用,并且可以传入参数
闭包函数的定义通常有以下几种方法

我们以第一种方式定义一个闭包函数,匿名函数可以作为变量的值来使用。此时 PHP 会自动把此种表达式转换成内置类Closure 的对象实例

<?php
    $url = function (){
        return 'http://c.biancheng.net/php/';
    };
?>

判断是不是闭包,有俩种方式,通过Closure内置类或者is_callable方法都可以判断

if($url instanceof Closure){
    echo '是匿名函数';
}else{
    echo '不是匿名函数';
}

if(is_callable($url)){
    echo '是匿名函数';
}else{
    echo '不是匿名函数';
}

闭包的调用

闭包说白了还是一个函数,所以调用闭包函数是在变量后面需要加上(),可能变量后面加()有点不适应,按照正常的思维,变量是直接调用,所以看到变量后面加()的,就知道该变量代表的是一个匿名函数。

echo $url();

闭包的序列化

$b=serialize($url);
$c=unserialize($url);
var_dump($c);

会报错

Fatal error: Uncaught Exception: Serialization of 'Closure' is not allowed in /Users/sftc/workerDir/sf-odp-2.0/script/xulie.php:114

可以看出闭包在php是不允许序列化的,那如果我们遇到了序列化的场景怎么办

  1. 安装序列化composer包
composer require opis/closure
  1. 序列化闭包
//(2).序列化闭包函数,输出序列化后的字符串
$b = \Opis\Closure\serialize($url);

//(3).反序列化闭包函数,执行还原的闭包函数
$c = \Opis\Closure\unserialize($b);
$c();
上一篇下一篇

猜你喜欢

热点阅读