Macroable Trait Kullanımı
Macroable Laravelde yoğun şekilde kullanılan bir trait.
Bir sınıfa runtime’da yetenekler kazandırmak için kullanılmaktadır. Bu sayede sınıfın kodlarına hiç dokunmadan dışardan eklenen methodlarla sınıf daha yetenekli hale getirilebilmektedir.
Sınıfa dışarıdan eklenen methodlar statik ve nesne yönelimli şekilde çağırılabilmektedir.
Macroable traiti aşağıdaki gibidir.
namespace Illuminate\Support\Traits;use Closure;
use BadMethodCallException;trait Macroable
{
/* macro methods storage */
protected static $macros = []; /* add new macro method to class on runtime */
public static function macro($name, callable $macro)
{
static::$macros[$name] = $macro;
} /* check is macro added */
public static function hasMacro($name)
{
return isset(static::$macros[$name]);
} /* magic method for static macro call */
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);
} /* magic method for instance method call */
public function __call($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(static::$macros[$method]->bindTo($this, static::class), $parameters);
} return call_user_func_array(static::$macros[$method], $parameters);
}
}
Geliştirdiğiniz sınıfta use Macroable şeklinde traiti ekleyerek runtime’da sınıfınız genişletilebilmesine destek verebilirsiniz.
/* test class */
class MacroableTestClass{ use Macroable; public function __construct()
{
}
}
Traitten gelen static macro() methodu ile sınıfımıza runtime’da method ekleyebilmekteyiz.
className::macro('methodName', function($param){
echo strtolower($param);
});Daha sonra nesne üstünden instance methodu veya sınıf üzerinden sınıf methodu şeklinde macrolar çağırılabilmektedir.
classname::macroMethod($param);
$object->macroMethod($param);Sihirli methodların kullanımına dikkat etmişsinizdir. Runtime’da eklediğimiz bu methodlar aslında sınıfın kendisinde(sınıf kaynak kodlarında) yoktur. Bundan dolayı bu methodların çağırımı __call ve __callstatic sihirli methodlarına gelmektedir.
Bu sihirli methodlar aracılığıyla çağırım yapılan method macro olarak var mı kontrol edilmekte ve macro varsa çalıştırılmaktadır.
Gelin bir örnek üstünden Macroable kullanımına daha yakından bakalım.
<?phpnamespace Illuminate\Support\Traits;use Closure;
use BadMethodCallException;trait Macroable
{
/* macro methods storage */
protected static $macros = []; /* add new macro method to class on runtime */
public static function macro($name, callable $macro)
{
static::$macros[$name] = $macro;
} /* check is macro added */
public static function hasMacro($name)
{
return isset(static::$macros[$name]);
} /* magic method for static macro call */
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);
} /* magic method for instance method call */
public function __call($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(static::$macros[$method]->bindTo($this, static::class), $parameters);
} return call_user_func_array(static::$macros[$method], $parameters);
}
}/* test class */
class MacroableTestClass{ use Macroable; public function __construct()
{ }
}MacroableTestClass::macro('macroMethod', function($testParam){
return $testParam;
});echo MacroableTestClass::macroMethod('macro test passed for static<br>');$obj = new MacroableTestClass();
echo $obj->macroMethod('macro test passed for instance<br>');/*
* OUTPUT
* macro test passed for static
* macro test passed for instance
*
*/
Gördüğünüz gibi sınıfa runtime’da macroMethod isminde bir method ekleyip daha sonra çağırabilmekteyim.
Burada önemli nokta şudur, Macroable tamamen sihirli methodlar üstünde kurulmuştur, yani eklediğiniz macro ile aynı isme sınıf methodu varsa bu sınıf methodu çağırılacaktır. Sihirli methodların çalışması için sınıfınızda bu methodun tanımlanmamış olması gerekmektedir.
/* test class */
class MacroableTestClass{ use Macroable; public function __construct()
{ }
/* if class has method with same name macro, class method run, because of when method found, __call magical method will not called */
public function macroMethod(){
return 'class has method same name with macro, then _call magical method will not triggered, class method runs <br>';
}
}MacroableTestClass::macro('macroMethod', function($testParam){
return $testParam;
});$obj = new MacroableTestClass();
echo $obj->macroMethod('macro test passed for instance<br>');
/*
* OUTPUT
* class has method same name with macro, then _call magical method will not triggered, class method runs */
*
*/
Umarım faydalı bir yazı olmuştur, kullanılmasını tavsiye ettiğim bir interface Macroable.
Önemli ve yararlı traitleri incelemeye devam edeceğiz.
Takipte Kalın.
