Analyse du processus en cours d'exécution du conteneur PHP Pimple

不言
Libérer: 2023-04-02 16:42:02
original
3507 Les gens l'ont consulté

Cet article présente principalement l'analyse du processus en cours du conteneur PHP Pimple, qui a une certaine valeur de référence. Maintenant, je le partage avec tout le monde. Les amis dans le besoin peuvent s'y référer

Connaissances nécessaires. points

Fermetures

Les fermetures et les fonctions anonymes ont été introduites dans PHP5.3.0.

Une fermeture fait référence à une fonction qui encapsule l'état environnant lors de sa création. Même si l’environnement dans lequel se situe la fermeture n’existe plus, l’état encapsulé dans la fermeture existe toujours.

Théoriquement, les fermetures et les fonctions anonymes sont des concepts différents. Mais PHP le traite comme le même concept.
En fait, les fermetures et les fonctions anonymes sont des objets déguisés en fonctions. Ce sont des instances de la classe Closure.

Les fermetures, comme les chaînes et les entiers, sont des types de valeurs de première classe.

Créer une fermeture :

<?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
Copier après la connexion
La raison pour laquelle nous pouvons appeler la variable $closure est parce que la valeur de cette variable est une fermeture, et l'objet de fermeture implémente la magie __invoke() méthode. Tant qu'il y a () après le nom de la variable, PHP trouvera et appellera la méthode __invoke().

Habituellement, les fermetures PHP sont utilisées comme rappels de fonctions. Les méthodes

array_map(), preg_replace_callback() utilisent toutes des fonctions de rappel. C'est le meilleur moment pour utiliser les fermetures !

Par exemple :

<?php
$numbersPlusOne = array_map(function ($number) {
    return $number + 1;
}, [1, 2, 3]);
print_r($numbersPlusOne);
Copier après la connexion

Obtenir le résultat :

[2, 3, 4]
Copier après la connexion

Avant les fermetures, vous ne pouviez créer que des fonctions nommées individuellement, puis référencer cette fonction par son nom . En faisant cela, l'exécution du code sera légèrement plus lente et l'implémentation du rappel sera isolée du scénario d'utilisation.

<?php
function incrementNum ($number) {
    return $number + 1;
}

$numbersPlusOne = array_map(&#39;incrementNum&#39;, [1, 2, 3]);
print_r($numbersPlusOne);
Copier après la connexion

SPL

ArrayAccess

Implémente l'interface ArrayAccess, qui permet aux objets de fonctionner comme des tableaux. L'interface ArrayAccess contient quatre méthodes qui doivent être implémentées :

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

SplObjectStorage

La classe SplObjectStorage implémente une carte avec des objets comme clés ou une collection d'objets (si les objets comme clés sont ignorés données correspondantes) cette structure de données. Une instance de cette classe ressemble beaucoup à un tableau, mais les objets qu’elle stocke sont tous uniques. Une autre fonctionnalité de cette classe est que vous pouvez directement en supprimer l'objet spécifié sans parcourir ni rechercher dans l'intégralité de la collection.

::class Syntaxe

Parce que ::class représente une chaîne. L'avantage d'utiliser ::class est que vous pouvez directement renommer une classe dans l'EDI, puis l'IDE gérera automatiquement les références pertinentes.
En même temps, lorsque PHP exécute le code concerné, il ne chargera pas d'abord la classe concernée.

De même, l'inspection automatisée du code peut également identifier correctement les classes.

Une brève analyse du processus du conteneur Pimple

Pimpl est un conteneur populaire dans la communauté PHP. Il n'y a pas beaucoup de code, voir https://github.com/silexphp/P... pour plus de détails.

Notre application peut être développée sur la base de 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);
    }
}
Copier après la connexion

Comment utiliser notre application :

$app = new Application([]);
$user = $app->user;
Copier après la connexion

Après cela, nous pouvons utiliser les méthodes du $user objet . Nous avons constaté qu'il n'y a pas d'attribut $this->user, mais il peut être utilisé directement. Principalement le rôle de ces deux méthodes :

public function offsetSet($id, $value){}
public function offsetGet($id){}
Copier après la connexion

Ci-dessous nous expliquerons ce que fait Pimple lors de l'exécution de ces deux lignes de code. Mais avant d’expliquer cela, examinons quelques concepts fondamentaux des conteneurs.

Fournisseur de services

Le fournisseur de services est le pont entre le conteneur et la classe d'implémentation de fonction spécifique. Les fournisseurs de services doivent implémenter l'interface 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);
}
Copier après la connexion

Tous les fournisseurs de services doivent implémenter les méthodes d'interface register.

Il y a 2 fournisseurs de services par défaut dans notre application :

protected $providers = [
    ServiceProviders\ServerServiceProvider::class,
    ServiceProviders\UserServiceProvider::class
];
Copier après la connexion

En prenant UserServiceProvider comme exemple, regardons son implémentation de code :

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;]);
        };
    }
}
Copier après la connexion

Nous voyons , la méthode d'enregistrement du fournisseur de services ajoutera des attributs user au conteneur, mais ce qui est renvoyé n'est pas un objet, mais une fermeture. J'expliquerai cela plus tard.

Enregistrement du service

Nous utilisons $this->registerProviders(); pour enregistrer tous les fournisseurs de services dans le constructeur de l'application :

private function registerProviders()
{
    foreach ($this->providers as $provider) {
        $this->register(new $provider());
    }
}
Copier après la connexion

En regardant attentivement, nous avons trouvé cette instance Le fournisseur de services est transformé et la méthode register du conteneur Pimple est appelée :

public function register(ServiceProviderInterface $provider, array $values = array())
{
    $provider->register($this);

    foreach ($values as $key => $value) {
        $this[$key] = $value;
    }

    return $this;
}
Copier après la connexion

Et ici la méthode register du fournisseur de services est appelée, ce que nous avons mentionné dans la section précédente : L'enregistrement. La méthode ajoute des attributs user au conteneur, mais renvoie non pas un objet, mais une fermeture.

Lorsque nous ajouterons des attributs user au conteneur Pimple, la méthode offsetSet($id, $value) sera appelée : attribuer des valeurs aux attributs values et keys du conteneur Pimple respectivement :

$this->values[$id] = $value;
$this->keys[$id] = true;
Copier après la connexion

À ce stade, nous n'avons pas instancié la classe EasyWeChatUserUsr qui fournit réellement la fonctionnalité réelle. Cependant, l'enregistrement du fournisseur de services est terminé.

Lorsque nous courons ici :

$user = $app->user;
Copier après la connexion

appellera offsetGet($id) et instanciera la vraie classe :

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

$this->frozen[$id] = true;

return $val;
Copier après la connexion

$raw obtient le package de fermeture :

$pimple[&#39;user&#39;] = function ($pimple) {
    return new User($pimple[&#39;access_token&#39;]);
};
Copier après la connexion

$raw($this) renvoie l'objet instancié User. Autrement dit, seul l’appel réel instanciera la classe spécifique. Plus tard, nous pourrons appeler des méthodes dans la classe User via $this['user'] ou $this->user.

Bien sûr, il existe de nombreuses fonctionnalités dans Pimple qui méritent notre étude approfondie, nous ne les expliquerons donc pas trop ici.

Ce qui précède représente l'intégralité du contenu de cet article. J'espère qu'il sera utile à l'étude de chacun. Pour plus de contenu connexe, veuillez faire attention au site Web PHP chinois !

Recommandations associées :

Comment wordpress utilise la fonction wp_head()

Portée, globale, statique des variables PHP Attendez pour les mots clés

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!