搜索
首页后端开发php教程Pimple运行流程浅析(PHP容器)

Pimple运行流程浅析(PHP容器)

需要具备的知识点

闭包

闭包和匿名函数在PHP5.3.0中引入的。

闭包是指:

创建时封装周围状态的函数。即使闭包所处的环境不存在了,闭包中封装的状态依然存在。

理论上,闭包和匿名函数是不同的概念。但是PHP将其视作相同概念。

实际上,闭包和匿名函数是伪装成函数的对象。他们是Closure类的实例。

闭包和字符串、整数一样,是一等值类型。

创建闭包:

<?php
$closure = function ($name) {
    return &#39;Hello &#39; . $name;
};
echo $closure(&#39;nesfo&#39;);//Hello nesfo
var_dump(method_exists($closure, &#39;__invoke&#39;));//true

我们之所以能调用$closure变量,是因为这个变量的值是一个闭包,而且闭包对象实现了__invoke()魔术方法。只要变量名后有(),PHP就会查找并调用__invoke()方法。

通常会把PHP闭包当作函数的回调使用。

array_map(), preg_replace_callback()方法都会用到回调函数,这是使用闭包的最佳时机!

举个例子:

<?php
$numbersPlusOne = array_map(function ($number) {
    return $number + 1;
}, [1, 2, 3]);
print_r($numbersPlusOne);

得到结果:

[2, 3, 4]

在闭包出现之前,只能单独创建具名函数,然后使用名称引用那个函数。这么做,代码执行会稍微慢点,而且把回调的实现和使用场景隔离了。

<?php
function incrementNum ($number) {
    return $number + 1;
}
$numbersPlusOne = array_map(&#39;incrementNum&#39;, [1, 2, 3]);
print_r($numbersPlusOne);

SPL

ArrayAccess

实现ArrayAccess接口,可以使得object像array那样操作。ArrayAccess接口包含四个必须实现的方法:

interface ArrayAccess {
    //检查一个偏移位置是否存在 
    public mixed offsetExists ( mixed $offset  );
    
    //获取一个偏移位置的值 
    public mixed offsetGet( mixed $offset  );
    
    //设置一个偏移位置的值 
    public mixed offsetSet ( mixed $offset  );
    
    //复位一个偏移位置的值 
    public mixed offsetUnset  ( mixed $offset  );
}

SplObjectStorage

SplObjectStorage类实现了以对象为键的映射(map)或对象的集合(如果忽略作为键的对象所对应的数据)这种数据结构。这个类的实例很像一个数组,但是它所存放的对象都是唯一。该类的另一个特点是,可以直接从中删除指定的对象,而不需要遍历或搜索整个集合。

::class语法

因为 ::class 表示是字符串。用 ::class 的好处在于 IDE 里面可以直接改名一个 class,然后 IDE 自动处理相关引用。

同时,PHP 执行相关代码时,是不会先加载相关 class 的。

同理,代码自动化检查 inspect 也可以正确识别 class。

Pimple容器流程浅析

Pimpl是php社区中比较流行的容器。代码不是很多,详见

https://github.com/silexphp/Pimple/blob/master/src/Pimple/Container.php 。

我们的应用可以基于Pimple开发:

namespace EasyWeChat\Foundation;
use Pimple\Container;
class Application extends Container
{
    /**
     * Service Providers.
     *
     * @var array
     */
    protected $providers = [
        ServiceProviders\ServerServiceProvider::class,
        ServiceProviders\UserServiceProvider::class
    ];
    /**
     * Application constructor.
     *
     * @param array $config
     */
    public function __construct($config)
    {
        parent::__construct();
        $this[&#39;config&#39;] = function () use ($config) {
            return new Config($config);
        };
        if ($this[&#39;config&#39;][&#39;debug&#39;]) {
            error_reporting(E_ALL);
        }
        $this->registerProviders();
    }
    /**
     * Add a provider.
     *
     * @param string $provider
     *
     * @return Application
     */
    public function addProvider($provider)
    {
        array_push($this->providers, $provider);
        return $this;
    }
    /**
     * Set providers.
     *
     * @param array $providers
     */
    public function setProviders(array $providers)
    {
        $this->providers = [];
        foreach ($providers as $provider) {
            $this->addProvider($provider);
        }
    }
    /**
     * Return all providers.
     *
     * @return array
     */
    public function getProviders()
    {
        return $this->providers;
    }
    /**
     * Magic get access.
     *
     * @param string $id
     *
     * @return mixed
     */
    public function __get($id)
    {
        return $this->offsetGet($id);
    }
    /**
     * Magic set access.
     *
     * @param string $id
     * @param mixed  $value
     */
    public function __set($id, $value)
    {
        $this->offsetSet($id, $value);
    }
}

如何使用我们的应用:

$app = new Application([]);
$user = $app->user;

之后我们就可以使用$user对象的方法了。我们发现其实并没有$this->user这个属性,但是可以直接使用。主要是这两个方法起的作用:

public function offsetSet($id, $value){}
public function offsetGet($id){}

下面我们将解释在执行这两句代码,Pimple做了什么。但在解释这个之前,我们先看看容器的一些核心概念。

服务提供者

服务提供者是连接容器与具体功能实现类的桥梁。服务提供者需要实现接口ServiceProviderInterface:

namespace Pimple;
/**
 * Pimple service provider interface.
 *
 * @author  Fabien Potencier
 * @author  Dominik Zogg
 */
interface ServiceProviderInterface
{
    /**
     * Registers services on the given container.
     *
     * This method should only be used to configure services and parameters.
     * It should not get services.
     *
     * @param Container $pimple A container instance
     */
    public function register(Container $pimple);
}

所有服务提供者必须实现接口register方法。

我们的应用里默认有2个服务提供者:

protected $providers = [
    ServiceProviders\ServerServiceProvider::class,
    ServiceProviders\UserServiceProvider::class
];

UserServiceProvider为例,我们看其代码实现:

namespace EasyWeChat\Foundation\ServiceProviders;
use EasyWeChat\User\User;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
/**
 * Class UserServiceProvider.
 */
class UserServiceProvider implements ServiceProviderInterface
{
    /**
     * Registers services on the given container.
     *
     * This method should only be used to configure services and parameters.
     * It should not get services.
     *
     * @param Container $pimple A container instance
     */
    public function register(Container $pimple)
    {
        $pimple[&#39;user&#39;] = function ($pimple) {
            return new User($pimple[&#39;access_token&#39;]);
        };
    }
}

我们看到,该服务提供者的注册方法会给容器增加属性user,但是返回的不是对象,而是一个闭包。这个后面我再做讲解。

服务注册

我们在Application里构造函数里使用$this->registerProviders();对所有服务提供者进行了注册:

private function registerProviders()
{
    foreach ($this->providers as $provider) {
        $this->register(new $provider());
    }
}

仔细看,我们发现这里实例化了服务提供者,并调用了容器Pimple的register方法:

public function register(ServiceProviderInterface $provider, array $values = array())
{
    $provider->register($this);
    foreach ($values as $key => $value) {
        $this[$key] = $value;
    }
    return $this;
}

而这里调用了服务提供者的register方法,也就是我们在上一节中提到的:注册方法给容器增加了属性user,但返回的不是对象,而是一个闭包。

当我们给容器Pimple添加属性user的同时,会调用offsetSet($id, $value)方法:给容器Pimple的属性values、keys分别赋值:

$this->values[$id] = $value;
$this->keys[$id] = true;

到这里,我们还没有实例化真正提供实际功能的类EasyWeChat\User\Usr。但已经完成了服务提供者的注册工作。

当我们运行到这里:

$user = $app->user;

会调用offsetGet($id)并进行实例化真正的类:

$raw = $this->values[$id];
$val = $this->values[$id] = $raw($this);
$this->raw[$id] = $raw;
$this->frozen[$id] = true;
return $val;

$raw获取的是闭包:

$pimple[&#39;user&#39;] = function ($pimple) {
    return new User($pimple[&#39;access_token&#39;]);
};

$raw($this)返回的是实例化的对象User。也就是说只有实际调用才会去实例化具体的类。后面我们就可以通过$this['user']或者$this->user调用User类里的方法了。

当然,Pimple里还有很多特性值得我们去深入研究,这里不做过多讲解。

更多相关php知识,请访问php教程

以上是Pimple运行流程浅析(PHP容器)的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文转载于:cnblogs。如有侵权,请联系admin@php.cn删除
PHP类型提示如何起作用,包括标量类型,返回类型,联合类型和无效类型?PHP类型提示如何起作用,包括标量类型,返回类型,联合类型和无效类型?Apr 17, 2025 am 12:25 AM

PHP类型提示提升代码质量和可读性。1)标量类型提示:自PHP7.0起,允许在函数参数中指定基本数据类型,如int、float等。2)返回类型提示:确保函数返回值类型的一致性。3)联合类型提示:自PHP8.0起,允许在函数参数或返回值中指定多个类型。4)可空类型提示:允许包含null值,处理可能返回空值的函数。

PHP如何处理对象克隆(克隆关键字)和__clone魔法方法?PHP如何处理对象克隆(克隆关键字)和__clone魔法方法?Apr 17, 2025 am 12:24 AM

PHP中使用clone关键字创建对象副本,并通过\_\_clone魔法方法定制克隆行为。1.使用clone关键字进行浅拷贝,克隆对象的属性但不克隆对象属性内的对象。2.通过\_\_clone方法可以深拷贝嵌套对象,避免浅拷贝问题。3.注意避免克隆中的循环引用和性能问题,优化克隆操作以提高效率。

PHP与Python:用例和应用程序PHP与Python:用例和应用程序Apr 17, 2025 am 12:23 AM

PHP适用于Web开发和内容管理系统,Python适合数据科学、机器学习和自动化脚本。1.PHP在构建快速、可扩展的网站和应用程序方面表现出色,常用于WordPress等CMS。2.Python在数据科学和机器学习领域表现卓越,拥有丰富的库如NumPy和TensorFlow。

描述不同的HTTP缓存标头(例如,Cache-Control,ETAG,最后修饰)。描述不同的HTTP缓存标头(例如,Cache-Control,ETAG,最后修饰)。Apr 17, 2025 am 12:22 AM

HTTP缓存头的关键玩家包括Cache-Control、ETag和Last-Modified。1.Cache-Control用于控制缓存策略,示例:Cache-Control:max-age=3600,public。2.ETag通过唯一标识符验证资源变化,示例:ETag:"686897696a7c876b7e"。3.Last-Modified指示资源最后修改时间,示例:Last-Modified:Wed,21Oct201507:28:00GMT。

说明PHP中的安全密码散列(例如,password_hash,password_verify)。为什么不使用MD5或SHA1?说明PHP中的安全密码散列(例如,password_hash,password_verify)。为什么不使用MD5或SHA1?Apr 17, 2025 am 12:06 AM

在PHP中,应使用password_hash和password_verify函数实现安全的密码哈希处理,不应使用MD5或SHA1。1)password_hash生成包含盐值的哈希,增强安全性。2)password_verify验证密码,通过比较哈希值确保安全。3)MD5和SHA1易受攻击且缺乏盐值,不适合现代密码安全。

PHP:服务器端脚本语言的简介PHP:服务器端脚本语言的简介Apr 16, 2025 am 12:18 AM

PHP是一种服务器端脚本语言,用于动态网页开发和服务器端应用程序。1.PHP是一种解释型语言,无需编译,适合快速开发。2.PHP代码嵌入HTML中,易于网页开发。3.PHP处理服务器端逻辑,生成HTML输出,支持用户交互和数据处理。4.PHP可与数据库交互,处理表单提交,执行服务器端任务。

PHP和网络:探索其长期影响PHP和网络:探索其长期影响Apr 16, 2025 am 12:17 AM

PHP在过去几十年中塑造了网络,并将继续在Web开发中扮演重要角色。1)PHP起源于1994年,因其易用性和与MySQL的无缝集成成为开发者首选。2)其核心功能包括生成动态内容和与数据库的集成,使得网站能够实时更新和个性化展示。3)PHP的广泛应用和生态系统推动了其长期影响,但也面临版本更新和安全性挑战。4)近年来的性能改进,如PHP7的发布,使其能与现代语言竞争。5)未来,PHP需应对容器化、微服务等新挑战,但其灵活性和活跃社区使其具备适应能力。

为什么要使用PHP?解释的优点和好处为什么要使用PHP?解释的优点和好处Apr 16, 2025 am 12:16 AM

PHP的核心优势包括易于学习、强大的web开发支持、丰富的库和框架、高性能和可扩展性、跨平台兼容性以及成本效益高。1)易于学习和使用,适合初学者;2)与web服务器集成好,支持多种数据库;3)拥有如Laravel等强大框架;4)通过优化可实现高性能;5)支持多种操作系统;6)开源,降低开发成本。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
1 个月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
1 个月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
1 个月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.聊天命令以及如何使用它们
1 个月前By尊渡假赌尊渡假赌尊渡假赌

热工具

Atom编辑器mac版下载

Atom编辑器mac版下载

最流行的的开源编辑器

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )专业的PHP集成开发工具

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

WebStorm Mac版

WebStorm Mac版

好用的JavaScript开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)