Pimple 実行プロセス (PHP コンテナー) の簡単な分析

藏色散人
リリース: 2023-04-08 09:42:01
転載
2690 人が閲覧しました

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 インターフェイスを実装します。配列 。 ArrayAccess インターフェイスには、実装する必要がある 4 つのメソッドが含まれています。

interface ArrayAccess {
    //检查一个偏移位置是否存在 
    public mixed offsetExists ( mixed $offset  );
    
    //获取一个偏移位置的值 
    public mixed offsetGet( mixed $offset  );
    
    //设置一个偏移位置的值 
    public mixed offsetSet ( mixed $offset  );
    
    //复位一个偏移位置的值 
    public mixed offsetUnset  ( mixed $offset  );
}
ログイン後にコピー

SplObjectStorage

SplObjectStorage クラスは、オブジェクトをキーまたはデータ構造として持つマップを実装します。それはオブジェクトのコレクションです (キーとしてオブジェクトに対応するデータを無視した場合)。このクラスのインスタンスは配列によく似ていますが、格納されるオブジェクトはすべて一意です。このクラスのもう 1 つの特徴は、コレクション全体を走査したり検索したりせずに、指定したオブジェクトをクラスから直接削除できることです。

::classSyntax

::class は文字列を表すためです。 ::class を使用する利点は、IDE で class の名前を直接変更できることです。その後、IDE が関連する参照を自動的に処理します。

同時に、PHP が関連コードを実行するときに、最初に関連クラスをロードしません。

同様に、自動コード検査

inspect もクラスを正しく識別できます。

Pimple コンテナー プロセスの簡単な分析

Pimple は、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 属性はありませんが、直接使用できることがわかりました。主にこれら 2 つのメソッドの役割:

public function offsetSet($id, $value){}
public function offsetGet($id){}
ログイン後にコピー

以下では、これら 2 行のコードを実行するときに 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;]);
        };
    }
}
ログイン後にコピー

us ご覧のとおり、サービス プロバイダーの登録メソッドは属性

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 をコンテナに追加しますが、オブジェクトではなくクロージャを返します。 属性 user をコンテナ Pimple に追加するとき、

offsetSet($id, $value)

メソッドを呼び出します。属性 values をコンテナ Pimple 、キーにはそれぞれ値が割り当てられます: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">$this-&gt;values[$id] = $value; $this-&gt;keys[$id] = true;</pre><div class="contentsignin">ログイン後にコピー</div></div>この時点まで、実際に提供するクラス

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 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:cnblogs.com
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!