Home  >  Article  >  Backend Development  >  Detailed explanation of Closure class in PHP

Detailed explanation of Closure class in PHP

小云云
小云云Original
2018-03-22 09:48:462569browse

This article mainly shares with you a detailed explanation of the Closure class in PHP. The PHP Closure class is a class used to represent anonymous functions. Anonymous functions (introduced in PHP 5.3) will generate objects of this type. The summary of the Closure class is as follows:

Closure {
    __construct ( void )
    public static Closure bind (Closure $closure , object $newthis [, mixed $newscope = 'static' ])
    public Closure bindTo (object $newthis [, mixed $newscope = 'static' ])
}

Method description:

Closure::__construct — Constructor used to prohibit instantiation
Closure::bind — Copy a closure and bind the specified $this object and class function area.
Closure::bindTo — Copies the current closure object and binds the specified $this object and class scope.

In addition to the methods listed here, there is also an __invoke method. This is for consistency with other objects that implement the __invoke() magic method, but the process of invoking the closure object has nothing to do with it.

Closure::bind and Closure::bindTo will be introduced below.

Closure::bind is the static version of Closure::bindTo. Its description is as follows:

public static Closure bind (Closure $closure , object $newthis [, mixed $newscope = 'static' ])

closure represents the closure object that needs to be bound.
newthis represents the object that needs to be bound to the closure object, or NULL to create an unbound closure.
newscope represents the class scope that you want to bind to the closure. You can pass in the class name or class example. The default value is 'static', which means no change.

This method returns a new Closure object when successful, and returns FALSE when failed.

Example description:

<?php
/** 
 * 复制一个闭包,绑定指定的$this对象和类作用域。 
 * 
 * @author 疯狂老司机 
 */
class Animal {
    private static $cat = "cat";
    private $dog = "dog";
    public $pig = "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实例公有成员属性
?>

Output:

cat
dog
pig

Closure::bindTo — Copy the current closure object and bind the specified $this object and class scope. The description is as follows:

public Closure Closure::bindTo (object $newthis [, mixed $newscope = &#39;static&#39; ])

newthis represents an object bound to the closure object, or NULL to cancel the binding.
newscope represents the class scope associated with the closure object. You can pass in the class name or class example. The default value is 'static', which means no change.

This method creates and returns a closure object, which binds the same variables as the current object, but can bind different objects or a new class scope. The bound object determines the value of $this in the returned closure object, and the class scope determines which methods the returned closure object can call. In other words, the methods that $this can call at this time work with the newscope class. The domain is the same.

Example 1:

<?php
function __autoload($class) {
    require_once "$class.php";
}

$template = new Template;
$template->render(new Article, &#39;tpl.php&#39;);
?>

Template.php template class

<?php
/** 
 * 模板类,用于渲染输出 
 * 
 * @author 疯狂老司机 
 */
class Template{
    /**
     * 渲染方法
     *
     * @access public 
     * @param obj 信息类
     * @param string 模板文件名
     */
    public function render($context, $tpl){
        $closure = function($tpl){
            ob_start();
            include $tpl;
            return ob_end_flush();
        };
        $closure = $closure->bindTo($context, $context);
        $closure($tpl);
    }

}

Article.php information class

<?php
/** 
 * 文章信息类 
 * 
 * @author 疯狂老司机 
 */
class Article{
    private $title = "这是文章标题";
    private $content = "这是文章内容";
}

tpl.php template file

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
    <head>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
    </head>
    <body>
        <h1><?php echo $this->title;?></h1>
        <p><?php echo $this->content;?></p>
    </body>
</html>

Make sure the above files are located in the same directory when running.

Output:

This is the article title

This is the article content

Example 2:

<?php
/** 
 * 给类动态添加新方法
 * 
 * @author 疯狂老司机
 */
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 疯狂老司机
 */
class Animal {
    use DynamicTrait;
    private $dog = &#39;dog&#39;;
}

$animal = new Animal;

// 往动物类实例中添加一个方法获取实例的私有属性$dog
$animal->getdog = function() {
    return $this->dog;
};

echo $animal->getdog();

?>

Output:

dog

Example 3:

<?php
/** 
 * 一个基本的购物车,包括一些已经添加的商品和每种商品的数量
 * 
 * @author 疯狂老司机
 */
class Cart {
    // 定义商品价格
    const PRICE_BUTTER  = 1.00;
    const PRICE_MILK    = 3.33;
    const PRICE_EGGS    = 8.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);

// 打出出总价格,其中有 5% 的销售税.
echo $my_cart->getTotal(0.05);

?>

Output:

132.88

Supplementary Note: Closures can use the USE key to connect external variables.

Summary: Proper use of closures can make the code more concise and refined.
Related recommendations:

Introduction to closure usage examples in php

Detailed explanation of closure usage examples in php

Introduction to closure in php

The above is the detailed content of Detailed explanation of Closure class in PHP. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn