PHP反射機制

PHP反射機制

PHP反射機制從PHP5開始支持,作業務開發的話應該不多接觸反射。我其實也是接觸很少,最近在學習laravel的"優雅",就接觸了到它其中的反射用法,已經我本身的見解想法。php

反射

按照以前的套路,咱們來看一下官方手冊,官方是怎麼說的。laravel

Reflection數組

PHP 5 具備完整的反射 API,添加了對類、接口、函數、方法和擴展進行反向工程的能力。 此外,反射 API 提供了方法來取出函數、類和方法中的文檔註釋。個人理解就是php反射機制能拿到類裏面的屬性方法,private 和 protected的也能夠閉包

  • 以上是官方文檔中給出的東西,說實話我看了感受沒什麼感受。
  • 能get到的點就是咱們可以經過這個窺探一個類全部信息,就像在別人的窗上桶了一個洞同樣。
  • 我應該怎麼用,或者基於什麼場景去用呢?這仍是很傷的。

laravel中的反射

laravel整個框架設計的"優雅"就是在於container、IOC、依賴注入。咱們來看一下容器中一段關於反射的代碼:
IlluminateContainerContainer:架構

/**
     * Instantiate a concrete instance of the given type.
     *
     * @param  string  $concrete
     * @param  array   $parameters
     * @return mixed
     *
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function build($concrete, array $parameters = [])
    {
        // If the concrete type is actually a Closure, we will just execute it and
        // hand back the results of the functions, which allows functions to be
        // used as resolvers for more fine-tuned resolution of these objects.
        if ($concrete instanceof Closure) {
            return $concrete($this, $parameters);
        }

        $reflector = new ReflectionClass($concrete);

        // If the type is not instantiable, the developer is attempting to resolve
        // an abstract type such as an Interface of Abstract Class and there is
        // no binding registered for the abstractions so we need to bail out.
        if (! $reflector->isInstantiable()) {
            if (! empty($this->buildStack)) {
                $previous = implode(', ', $this->buildStack);

                $message = "Target [$concrete] is not instantiable while building [$previous].";
            } else {
                $message = "Target [$concrete] is not instantiable.";
            }

            throw new BindingResolutionException($message);
        }

        $this->buildStack[] = $concrete;

        $constructor = $reflector->getConstructor();

        // If there are no constructors, that means there are no dependencies then
        // we can just resolve the instances of the objects right away, without
        // resolving any other types or dependencies out of these containers.
        if (is_null($constructor)) {
            array_pop($this->buildStack);

            return new $concrete;
        }

        $dependencies = $constructor->getParameters();

        // Once we have all the constructor's parameters we can create each of the
        // dependency instances and then use the reflection instances to make a
        // new instance of this class, injecting the created dependencies in.
        $parameters = $this->keyParametersByArgument(
            $dependencies, $parameters
        );

        $instances = $this->getDependencies(
            $dependencies, $parameters
        );

        array_pop($this->buildStack);

        return $reflector->newInstanceArgs($instances);
    }

就是實現綁定類的方法,build方法。下面咱們就來分析一下:框架

  • 參數:$concreate string 相似於Model::class這種嘛,不難理解。$parameters array 參數 更不難理解了吧。
  • 判斷 $concreate 是不是匿名類(閉包),是匿名類就執行這個函數.
  • 建立反射類,去映射這個類。
  • 判斷這個類可否被實例化,也就是看構造函數是不是private。否就拋出出異常。
  • 在容器成員變量中數組維護這個類,反射實例調用構造函數,獲取返回值。
  • 判斷返回值是否爲空,若是爲空就說明不須要參數依賴,那麼就直接實例化。不然就獲取構造函數的參數依賴,將傳入的參數和依賴參數進行對照。
  • 最後,在調用newInstanceArgs進行實例化,以後返回實例。

後記

其實在上面這個laravel中的例子已經很好的闡明瞭反射機制的使用方式,或許你如今的業務場景還未必可以使用到這種機制。可是,當碰到的時候請記得還有這種方式可以使用。函數

  • 當你須要去實例化一個類,可是這個類對你來講徹底就是封閉或者說是未知的,你能夠建立反射來與映射這個類,經過一系列的探測來最終實例化這個類,尤爲還在動態運行中的。
  • 基於這種機制,其實能夠玩出不少的花樣。好比說可以自動生成文檔。
  • 實現MVC這種架構,使用反射自動調用實現
$class = new ReflectionClass(ucfirst($controller));
$controller = $class->newInstance();
if ($class->hasMethod($method)) {
    $method = $class->getMethod($method);
    $method->invokeArgs($controller, $arguments);
} else {
    throw new Exception("{$controller} controller method {$method} not exists!");
}
  • 實現單元測試
$class = new ReflectionClass($class);
    if ($class->hasMethod($method)) {
        $method = $class->getMethod($method);
        $object = $class->newInstance();
        $class = $method->invokeArgs(new $object, $params);
        var_dump($res === $assert);
    }
  • laravel中的反射幫助它解決DI容器的依賴注入的問題。

還有不少好玩的等着你本身去嘗試,這種機制究竟能玩出多少花樣,就看你本身怎麼玩了。單元測試

相關文章
相關標籤/搜索