この記事では主にPHPコンテナ「Pimple」の実行プロセスの解析を紹介していますが、一定の参考値があるので皆さんに共有します。困っている友人は参考にしてください。
クロージャーと匿名関数は PHP5.3.0 で導入されました。
クロージャは、作成時に周囲の状態をカプセル化する関数を指します。クロージャが配置されている環境が存在しなくなっても、クロージャにカプセル化された状態は依然として存在します。
理論的には、クロージャと匿名関数は異なる概念です。しかし、PHP ではこれを同じ概念として扱います。
実際には、クロージャと匿名関数は関数に見せかけたオブジェクトです。これらは Closure クラスのインスタンスです。
クロージャは、文字列や整数と同様、第一級の値型です。
クロージャの作成:
<?php $closure = function ($name) { return 'Hello ' . $name; }; echo $closure('nesfo');//Hello nesfo var_dump(method_exists($closure, '__invoke'));//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('incrementNum', [1, 2, 3]); print_r($numbersPlusOne);
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 クラスは、オブジェクトをキーとして使用するマップ (マップ)、またはオブジェクトのコレクション (対応するオブジェクトを無視した場合) を実装します。キーデータへ)このデータ構造。このクラスのインスタンスは配列によく似ていますが、格納されるオブジェクトはすべて一意です。このクラスのもう 1 つの特徴は、コレクション全体を走査したり検索したりせずに、指定したオブジェクトをクラスから直接削除できることです。
::class
構文::class
は文字列を表すためです。 ::class
を使用する利点は、IDE でクラスの名前を直接変更でき、IDE が関連する参照を自動的に処理することです。
同時に、PHP が関連コードを実行するときに、最初に関連クラスをロードしません。
同様に、自動コード検査でもクラスを正しく識別できます。
Pimple は、PHP コミュニティで人気のあるコンテナーです。コードはそれほど多くありません。詳細については、https://github.com/silexphp/P... を参照してください。
私たちのアプリケーションは 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['config'] = function () use ($config) { return new Config($config); }; if ($this['config']['debug']) { 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){}
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 メソッドを実装する必要があります。
protected $providers = [ ServiceProviders\ServerServiceProvider::class, ServiceProviders\UserServiceProvider::class ];
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['user'] = function ($pimple) { return new User($pimple['access_token']); }; } }
user をコンテナに追加しますが、返されるのはオブジェクトではなくクロージャです。これについては後ほど説明します。
$this->registerProviders(); を使用して、すべてのサービス プロバイダーを登録します。注意して見てみると、ここでサービス プロバイダーがインスタンス化されており、コンテナ Pimple の
register
private function registerProviders() { foreach ($this->providers as $provider) { $this->register(new $provider()); } }
そして、ここでサービス プロバイダーの
register が # と呼ばれています。 ## メソッドは前のセクションで説明したものです。登録メソッドは属性 user をコンテナに追加しますが、オブジェクトではなくクロージャを返します。 属性
user
をコンテナ Pimple に追加すると、
メソッドが呼び出されます。コンテナ Pimple 、
keys の属性がそれぞれ割り当てられます:
public function register(ServiceProviderInterface $provider, array $values = array()) { $provider->register($this); foreach ($values as $key => $value) { $this[$key] = $value; } return $this; }
この時点まで、クラス
EasyWeChat\User\Usr をインスタンス化していません。実際に実際の機能を提供します。ただし、サービスプロバイダーの登録は完了しています。
ここで実行すると: $this->values[$id] = $value; $this->keys[$id] = true;
は
offsetGet($id) を呼び出し、実際のクラスをインスタンス化します: $user = $app->user;
$raw はクロージャを取得します。
$raw = $this->values[$id]; $val = $this->values[$id] = $raw($this); $this->raw[$id] = $raw; $this->frozen[$id] = true; return $val;
$raw($this) はインスタンス化されたオブジェクト User を返します。つまり、実際の呼び出しのみが特定のクラスをインスタンス化します。後で、
$this['user']
$this->user を通じて User クラスのメソッドを呼び出すことができます。
もちろん、Pimple には徹底的に研究する価値のある機能がたくさんあるので、ここではあまり説明しません。
上記がこの記事の全内容です。皆様の学習に役立つことを願っています。その他の関連コンテンツについては、PHP 中国語 Web サイトに注目してください。
関連する推奨事項:
PHP 変数のスコープ、グローバル、静的キーワードを待ちます
以上がPHPコンテナPimpleの実行プロセスの解析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。