Maison  >  Article  >  développement back-end  >  Comment utiliser les macros macroables dans Laravel

Comment utiliser les macros macroables dans Laravel

不言
不言original
2018-07-10 14:10:482989parcourir

Cet article présente principalement l'utilisation des macros Macroable dans Laravel. Il a une certaine valeur de référence. Maintenant, je le partage avec vous. Les amis dans le besoin peuvent s'y référer

Définition de l'Encyclopédie Baidu :
Macro dans. l'informatique est un terme désignant le traitement par lots. De manière générale, une macro est une règle ou un modèle, ou une substitution de syntaxe, utilisée pour expliquer comment une entrée spécifique (généralement une chaîne) est convertie en une sortie correspondante (généralement une chaîne) selon des règles prédéfinies. Ce remplacement se produit au moment de la précompilation et est appelé extension de macro.
  • Je suis entré en contact pour la première fois avec les macros alors que je suivais un cours d'informatique de base à l'université et le professeur m'a parlé du bureau. A cette époque, l'enseignant n'y prêtait pas beaucoup d'attention lorsqu'il introduisait l'opération macro. Il se souvenait seulement que cette opération était très puissante et qu'elle pouvait faciliter le travail quotidien.

  • Aujourd'hui, nous allons parler des opérations de macro dans Laravel


Tout d'abord, le code source complet

<?php

namespace Illuminate\Support\Traits;

use Closure;
use ReflectionClass;
use ReflectionMethod;
use BadMethodCallException;

trait Macroable
{
    /**
     * The registered string macros.
     *
     * @var array
     */
    protected static $macros = [];

    /**
     * Register a custom macro.
     *
     * @param  string $name
     * @param  object|callable  $macro
     *
     * @return void
     */
    public static function macro($name, $macro)
    {
        static::$macros[$name] = $macro;
    }

    /**
     * Mix another object into the class.
     *
     * @param  object  $mixin
     * @return void
     */
    public static function mixin($mixin)
    {
        $methods = (new ReflectionClass($mixin))->getMethods(
            ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_PROTECTED
        );

        foreach ($methods as $method) {
            $method->setAccessible(true);

            static::macro($method->name, $method->invoke($mixin));
        }
    }

    /**
     * Checks if macro is registered.
     *
     * @param  string  $name
     * @return bool
     */
    public static function hasMacro($name)
    {
        return isset(static::$macros[$name]);
    }

    /**
     * Dynamically handle calls to the class.
     *
     * @param  string  $method
     * @param  array   $parameters
     * @return mixed
     *
     * @throws \BadMethodCallException
     */
    public static function __callStatic($method, $parameters)
    {
        if (! static::hasMacro($method)) {
            throw new BadMethodCallException("Method {$method} does not exist.");
        }

        if (static::$macros[$method] instanceof Closure) {
            return call_user_func_array(Closure::bind(static::$macros[$method], null, static::class), $parameters);
        }

        return call_user_func_array(static::$macros[$method], $parameters);
    }

    /**
     * Dynamically handle calls to the class.
     *
     * @param  string  $method
     * @param  array   $parameters
     * @return mixed
     *
     * @throws \BadMethodCallException
     */
    public function __call($method, $parameters)
    {
        if (! static::hasMacro($method)) {
            throw new BadMethodCallException("Method {$method} does not exist.");
        }

        $macro = static::$macros[$method];

        if ($macro instanceof Closure) {
            return call_user_func_array($macro->bindTo($this, static::class), $parameters);
        }

        return call_user_func_array($macro, $parameters);
    }
}
  • Macroable::macroMéthode

public static function macro($name, $macro)
{
    static::$macros[$name] = $macro;
}

Code très simple, d'après le commentaire du paramètre, $macro peut passer une fermeture ou un objet, la raison pour laquelle les objets peuvent être passés est grâce à la méthode magique

class Father
{
    // 通过增加魔术方法**__invoke**我们就可以把对象当做闭包来使用了。
    public function __invoke()
    {
        echo __CLASS__;
    }
}

class Child
{
    use \Illuminate\Support\Traits\Macroable;
}

// 增加了宏指令之后,我们就能调用 Child 对象中不存在的方法了
Child::macro('show', new Father);
// 输出:Father
(new Child)->show();
  • méthode

    Macroable::mixin

  • en
PHP

>Cette méthode consiste à injecter le résultat de retour de la méthode d'un objet dans l'objet d'origine

public static function mixin($mixin)
{
    // 通过反射获取该对象中所有公开和受保护的方法
    $methods = (new ReflectionClass($mixin))->getMethods(
        ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_PROTECTED
    );

    foreach ($methods as $method) {
        // 设置方法可访问,因为受保护的不能在外部调用
        $method->setAccessible(true);
        
        // 调用 macro 方法批量创建宏指令
        static::macro($method->name, $method->invoke($mixin));
    }
}

// 实际使用
class Father
{
    public function say()
    {
        return function () {
            echo 'say';
        };
    }

    public function show()
    {
        return function () {
            echo 'show';
        };
    }

    protected function eat()
    {
        return function () {
            echo 'eat';
        };
    }
}

class Child
{
    use \Illuminate\Support\Traits\Macroable;
}

// 批量绑定宏指令
Child::mixin(new Father);

$child = new Child;
// 输出:say
$child->say();
// 输出:show
$child->show();
// 输出:eat
$child->eat();

Comme vous pouvez le voir dans le code ci-dessus, mixin peut lier une classe méthode à une classe de macro. Il convient de noter que la méthode doit renvoyer un type de fermeture.

  • Macroable::hasMacroMéthode

public static function hasMacro($name)
{
    return isset(static::$macros[$name]);
}

Cette méthode est relativement simple et pas compliquée du tout. Elle détermine simplement s'il existe une macro. instruction. C'est généralement une bonne idée de vérifier avant d'utiliser des macros. Méthodes

  • Macroable::__call et Macroable::__callStatic

C'est grâce à ces deux méthodes que nous pouvons effectuer des opérations de macro en plus de The. les méthodes d'exécution sont différentes, mais les codes sont pour la plupart les mêmes. Parlons de __call

public function __call($method, $parameters)
{
    // 如果不存在这个宏指令,直接抛出异常
    if (! static::hasMacro($method)) {
        throw new BadMethodCallException("Method {$method} does not exist.");
    }

    // 得到存储的宏指令
    $macro = static::$macros[$method];

    // 闭包做一点点特殊的处理
    if ($macro instanceof Closure) {
        return call_user_func_array($macro->bindTo($this, static::class), $parameters);
    }

    // 不是闭包,比如对象的时候,直接通过这种方法运行,但是要确保对象有`__invoke`方法
    return call_user_func_array($macro, $parameters);
}


class Child
{
    use \Illuminate\Support\Traits\Macroable;

    protected $name = 'father';
}

// 闭包的特殊处理,需要做的就是绑定 $this, 如
Child::macro('show', function () {
    echo $this->name;
});

// 输出:father
(new Child)->show();

dans l'opération ci-dessus Lorsque nous lions la macro, les propriétés de $this peuvent être appelées via Child dans la fermeture car dans la méthode __call Ici. nous utilisons la méthode Closure::bindTo.

Explication du site officiel de Closure::bindTo : copiez l'objet de fermeture actuel et liez l'objet $this spécifié et la portée de la classe.

Ajouter des macros aux classes dans Laravel

De nombreuses classes dans Laravel utilisent des macros trait



Par exemple, IlluminateFilesystemFilesystem::class, nous voulons ajouter une méthode à cette classe, mais nous ne toucherons pas au code qu'elle contient.

  1. Il suffit d'ajouter des macros à la méthode AppProvidersAppServiceProvider::register (vous pouvez également créer un nouveau fournisseur de services pour le gérer spécifiquement)


1. Ajoutez ensuite un itinéraire test pour tester notre méthode nouvellement ajoutée


2. Ensuite, ouvrez le navigateur et exécutez-le, vous constaterez que notre code peut s'exécuter normalement et afficher les résultats

Ce qui précède est l'intégralité du contenu de cet article, J'espère que cela sera utile. L'apprentissage de tout le monde est utile. Pour plus de contenu connexe, veuillez faire attention au site Web PHP chinois !

Recommandations associées :

Analyse de l'ORM éloquent de Laravel

Analyse des migrations de base de Laravel

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!

Déclaration:
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