This article mainly introduces the use of macroable macros in Laravel, has a certain reference value, now share to everyone, the need for friends can refer to
the definition of Baidu Encyclopedia:
Macro in computer science is a kind of title for batch processing. Generally, a macro is a rule or pattern, or syntax substitution, that describes how a particular input (usually a string) is converted to the corresponding output (usually a string) based on a predefined rule. This substitution occurs during precompilation, called macro expansion.
The first time I came in touch with a macro was when my teacher spoke office when I was in college on computer fundamentals. When the teacher introduced the macro operation did not care too much, only remember that this operation is very powerful, it can make the daily work easier.
Today we are talking about macro operations in Laravel
The first complete source code
<?phpnamespace 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 FUNCTI On macro ($name, $macro) {static:: $macros [$name] = $macro; }/** * Mix another object into the class. * * @param object $mixin * @return void */public static function Mixin ($mixin) {$methods = (n EW 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 is Set (static:: $macros [$name]); }/** * Dynamically handle calls to the class. * * @param string $method * @param array $parameters * @return Mixed * * @throws \badmethodcallex Ception */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 \badmethodcallex Ception */Public Function __call ($method, $parameters) {if (! Static::hasmacro ($method)) {throw new Badm Ethodcallexception ("Method {$method} does not exist."); } $macro = static:: $macros [$method]; if ($macro instanceof Closure) {return Call_user_func_array ($macro->bindto ($this, Static::class), $paramete RS); } return Call_user_func_array ($macro, $parameters); }}
public static function Macro ($name, $macro) { static:: $macros [$name] = $macro;}
Very simple code, according to the parameters of the comments, $macro
can be passed a closure or object, the reason can be transmitted to the object, thanks to the Magic method in PHP
Class father{ //By adding the Magic method **__invoke** we can use the object as a closure. Public function __invoke () { echo __class__; }} Class child{use \illuminate\support\traits\macroable;} With the addition of macros, we can invoke methods that do not exist in the child object Child::macro (' Show ', new Father);//output: Father (New Child)->show ();
This method injects the return result of an object's method into the original object
public static function Mixin ($mixin) {//gets all the exposed and protected methods in the object by reflection $methods = (new Reflectionclass ($mixin))->getmethods (Reflectionmethod::is_public | reflectionmethod::is_protected); The foreach ($methods as $method) {//setting method is accessible because the protected cannot be called externally $method->setaccessible (true); Call the macro method to bulk Create macros Static::macro ($method->name, $method->invoke ($mixin)); }}//actually uses the 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;} Bulk bound macro directive child::mixin (new Father); $child = new child;//output: Say$child->say ();//output: Show$child->show ();//output: eat$ Child->eat ();
As you can see in the code above, mixin
you can bind a method of a class to a macro class. It is important to note that the method must return a closure type.
public static function Hasmacro ($name) { return isset (static:: $macros [$name]);}
This method is relatively simple and there is nothing complicated to judge whether there is a macro directive. This is usually preceded by the use of macro directives.
Just because of these two methods, we can do macro operation, two methods in addition to the implementation of different ways, the code is similar. Here, let's talk.__call
Public Function __call ($method, $parameters) { //If this macro is not present, throw the exception directly if (! Static::hasmacro ($method)) { throw new Badmethodcallexception ("Method {$method} does not exist."); The macro command that gets stored $macro = static:: $macros [$method]; Closures do a little bit of special handling if ($macro instanceof Closure) { return Call_user_func_array ($macro->bindto ($this, Static:: Class), $parameters); } Not closures, such as objects, run directly through this method, but make sure that the object has a ' __invoke ' method return Call_user_func_array ($macro, $parameters);} Class child{use \illuminate\support\traits\macroable; protected $name = ' father ';} The special handling of closures, the need to do is to bind $this, such as Child::macro (' Show ', function () { echo $this->name;}); /output: Father (new Child)->show ();
In the above operation, when we bind a macro, we can $this
invoke the property in the closure Child
, because __call
we use the method in the method Closure::bindTo
.
explanation of the official website
Closure::bindTo
: Copy the current closure object, binding the specified $this object and the class scope.
Adding macro directives to classes in Laravel
There are many classes in Laravel that use macros.trait
For example Illuminate\Filesystem\Filesystem::class
, we want to add a method to this class, but we don't move the code inside.
We only need to App\Providers\AppServiceProvider::register
add macro instructions to the method (you can also create a new service provider specifically to handle)
1. Then add a test route to test our new added method
2. Then open the browser to run, you will find that our code can run properly and output the results
The above is the whole content of this article, I hope that everyone's learning has helped, more relevant content please pay attention to topic.alibabacloud.com!