美文网首页
回调函数和闭包(匿名函数)以及闭包的序列化

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

作者: PENG先森_晓宇 | 来源:发表于2022-04-11 16:57 被阅读0次

    回调函数

    回调函数: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这个方法的封装,有俩大特点需要注意下:

    • 创建不同的数据库需要不同的con类,所以这里让用户自行实现,第二个参数指定为con类。
    • call_user_func_array(callable $callback, array $param_arr): mixed
      调用回调函数,并把一个数组参数作为回调函数的参数
    • call_user_func(callable $callback): mixed 也是调用回调函数的,和上面那个的区别就是这里没有第二个参数,只有一个回调函数参数。
    • call_user_func([$this, 'test'], ...$this->params),其实call_user_func和call_user_func_array函数并不是只可调用回调函数,普通的方法也可以调。像这个表达式指的是调用本类的test方法,省去了new实例了

    闭包(匿名函数)

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

    闭包的定义

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

    • 直接赋值:$func_name = function($arg){statement}
    • 直接使用匿名函数,在参数处直接定义函数,不赋给具体的变量值,也就是上面回调函数定义的方式;

    我们以第一种方式定义一个闭包函数,匿名函数可以作为变量的值来使用。此时 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();
    

    相关文章

      网友评论

          本文标题:回调函数和闭包(匿名函数)以及闭包的序列化

          本文链接:https://www.haomeiwen.com/subject/fhnrsrtx.html