关于laravel 使用__call,__callStatic实现静态,动态方法互相调用

2022年2月11日13:37:13

 觉得laravel orm好用的时候,我一直想去花时间了解是为什么,但是工作一直都挺忙的,最近自己在写一些东西的时候,为了防止调用方式不对

看了下源码:

 

$counter = AdminLog::where('is_delete', GlobalCode::NORMAL);

我通过静态调用追查源码发现这个类其实是动态方法

    public function where($column, $operator = null, $value = null, $boolean = 'and')
    {
        if ($column instanceof Closure && is_null($operator)) {
            $column($query = $this->model->newQueryWithoutRelationships());

            $this->query->addNestedWhereQuery($query->getQuery(), $boolean);
        } else {
            $this->query->where(...func_get_args());
        }

        return $this;
    }

继承的模型的Model 调用的 Builder 

Model的call

    public function __call($method, $parameters)
    {
        if (in_array($method, ['increment', 'decrement'])) {
            return $this->$method(...$parameters);
        }

        if ($resolver = (static::$relationResolvers[get_class($this)][$method] ?? null)) {
            return $resolver($this);
        }

        return $this->forwardCallTo($this->newQuery(), $method, $parameters);
    }

    /**
     * Handle dynamic static method calls into the model.
     *
     * @param  string  $method
     * @param  array  $parameters
     * @return mixed
     */
    public static function __callStatic($method, $parameters)
    {
        return (new static)->$method(...$parameters);
    }

Build的call

public function __call($method, $parameters)
    {
        if ($method === 'macro') {
            $this->localMacros[$parameters[0]] = $parameters[1];

            return;
        }

        if ($this->hasMacro($method)) {
            array_unshift($parameters, $this);

            return $this->localMacros[$method](...$parameters);
        }

        if (static::hasGlobalMacro($method)) {
            $callable = static::$macros[$method];

            if ($callable instanceof Closure) {
                $callable = $callable->bindTo($this, static::class);
            }

            return $callable(...$parameters);
        }

        if ($this->hasNamedScope($method)) {
            return $this->callNamedScope($method, $parameters);
        }

        if (in_array($method, $this->passthru)) {
            return $this->toBase()->{$method}(...$parameters);
        }

        $this->forwardCallTo($this->query, $method, $parameters);

        return $this;
    }

    /**
     * Dynamically handle calls into the query instance.
     *
     * @param  string  $method
     * @param  array  $parameters
     * @return mixed
     *
     * @throws \BadMethodCallException
     */
    public static function __callStatic($method, $parameters)
    {
        if ($method === 'macro') {
            static::$macros[$parameters[0]] = $parameters[1];

            return;
        }

        if ($method === 'mixin') {
            return static::registerMixin($parameters[0], $parameters[1] ?? true);
        }

        if (! static::hasGlobalMacro($method)) {
            static::throwBadMethodCallException($method);
        }

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

        if ($callable instanceof Closure) {
            $callable = $callable->bindTo(null, static::class);
        }

        return $callable(...$parameters);
    }

核心的方法就是 __call,__callStatic的互相使用

    public function __call($method, $parameters)
    {
        return $this->$method(...$parameters);
    }

    public static function __callStatic($method, $parameters)
    {
        return (new static)->$method(...$parameters);
    }

这就是核心的部分

举个例子

test.php

<?php

include_once './p.php';
include_once './pp.php';

$a = new pp();
$a->notify(1111);
echo PHP_EOL;
//$a->aa(1111);

//pp::notify(1111);

p.php 父类

<?php

class p
{
    public function notify($ddd)
    {
        print_r(get_class($this) . 'notify111111111');
        echo PHP_EOL;
    }

    public static function refund()
    {
        echo self::class . 'refund';
    }
    public function __call($method, $parameters)
    {
        return $this->$method(...$parameters);
    }

    public static function __callStatic($method, $parameters)
    {
        return (new static)->$method(...$parameters);
    }
}

pp.php 子类

<?php

class pp extends p
{
    // public function notify($ddd)
    // {
    //     print_r(get_class($this) . 'notify111111111');
    //     echo PHP_EOL;
    // }

    // public static function refund()
    // {
    //     echo self::class . 'refund';
    // }

}

 

注意事项:

1,继承父类和子类的时候,如果调用子类的方法的时候,子类方法必须要是protect或者更少的权限,因为会报警告

2,继承父类和子类的时候,如果方法是父类的如果方法,父类就不会报警告信息

3,如果子类,或者当前类有public,会先找public,如果没有在调用call,callStatic魔术方法

4,如果你需要设计成这样的 方法,请注意类的权限,不然会有很多小问题

 

posted on 2022-02-11 16:47  zh7314  阅读(302)  评论(0编辑  收藏  举报