From Apprentice To Artisan 翻譯 04

上一篇php

Reflect Resolution 反射解決方案

One of the most powerful features of the Laravel container is its ability to automatically resolve dependencies via reflection. Reflection is the ability to inspect a classes and methods. For example, the PHP ReflectionClass class allows you to inspect the method avaliable on a given class. The PHP method method_exists is also a form of reflection. To play with PHP's reflection class, try the followring code on one of your classes:app

用反射來自動處理依賴是Laravel容器的一個最強大的特性。反射是一種運行時探測類和方法的能力。好比,PHP的ReflectionClass能夠探測一個類的方法。method_exists某種意義上說也是一種反射。咱們來把玩一下PHP的反射類,試試下面的代碼吧(StripeBiller換成你本身定義好的類):ide

<!-- lang: php -->
$reflection = new ReflectionClass('StripeBiller');
var_dump($reflection->getMethods());
var_dump($reflection->getConstants());

By leveraging this powerful feature of PHP, the Laravel IoC container can do some interesting things! For instance, consider the following class:函數

依靠這個強大的PHP特性, Laravel的IoC容器能夠實現頗有趣的功能!考慮接下來這個類:ui

<!-- lang:php -->
class UserController extends BaseController
{
    public function __construct(StripBiller $biller)
    {
        $this->biller = $biller;
    }
}

Note that the controller is type-hinting the StripBiller class. We are able to retrieve this type-hint using reflection. When the Laravel container does not have a resolver for a class explictity bound, it will try to resolve the class via reflection. The flow looks like this:this

注意這個控制器的構造函數暗示着有一個StripBiller類型的參數。使用反射就能夠檢測到這種類型暗示。當Laravel的容器沒法解決一個類型的明顯綁定時,容器會試着使用反射來解決。程序流程相似於這樣的:.net

  1. Do I have a resolver for StripBiller?rest

    已經有一個StripBiller的綁定了麼?code

  2. No resolver? Reflect into StripBiller to determin if it has dependencies.orm

    沒綁定?那用反射來探測一下StripBiller吧。看看他都須要什麼依賴。

  3. Resolve any dependencies needed by StripBiller (recursive).

    解決StripBiller須要的全部依賴(遞歸處理)

  4. Instantiate new StripBiller instance via ReflectionClass->newInstanceArgs().

    使用ReflectionClass->newInstanceArgs()來實例化StripBiller

As you can see, the container is doing a lot of heavy lifting for you, which saves you from having to write resolves for every single one of your classes. This is one of the most powerful and unique features of the Laravel container, and having a strong grasp of this capability is very beneficial when building large Laravel applications.

如你所見, 容器替咱們作了好多重活,這能幫你省去寫大量綁定的麻煩。這就是Laravel容器最強大也是最獨特的特性。熟練掌握這種能力對構建大型Laravel應用是十分有益的。

Now, let's modify our controller a bit. What if it looks like this?

下面咱們修改一下控制器, 改爲這樣會發生什麼事兒呢?

<!-- lang:php -->
class UserController extends BaseController
{
    public function __construct(BillerInterface $biller)
    {
        $this->biller = $biller;
    }
}

Assuming we have not explicitly bound a resolver for BillerInterface, how will the container know what class to inject? Remember, interface can't be instantiated since they are just contracts. Without us giving the container any more information, it will be unable to instantiate this dependency. We need to specify a class that should be used as the default implementation of this interface, and we may do so via the bind method:

假設咱們沒有爲BillerInterface作任何綁定, 容器該怎麼知道要注入什麼類呢?要知道,interface不能被實例化,由於它只是個約定。若是咱們不提供更多信息的話,容器是沒法實例化這個依賴的。咱們須要明確指出哪一個類要實現這個接口,這就須要用到bind方法:

<!-- lang:php -->
App::bind('BillerInterface','StripBiller');

Here, we are passing a string instead of a Closure, and this string tells the container to always use the StripBiller class anytime it needs an implementation of the BillerInterface interface. Again, we're gaining the ability to switch implementations of services with a simple one-line change to our container binding. For example, if we need to switch to Balanced Payments as our billing provider, we simply write a new BalancedBiller implementation of BillerInterface, and change our container binding:

這裏咱們只傳了一個字符串進去,而不是一個匿名函數。 這個字符串告訴容器老是使用StripBiller來做爲BillerInterface的實現類。 此外咱們也得到了只改一行代碼便可輕鬆改變實現的能力。好比,假設咱們須要切換到Balanced Payments做爲咱們的支付提供商,咱們只須要新寫一個BalancedBiller來實現BillerInterface接口,而後這樣修改容器代碼:

<!-- lang:php -->
App::bind('BillerInterface', 'BalancedBiller');

Automatically, our new implementation will be used throughout out application!

咱們的應用程序就裝載上了的新支付實現代碼了!

When binding implementations to interfaces, you may also use the singleton method so the container only instantiates one instance of the class per request cycle:

你也可使用singleton方法來實現單例模式。

<!-- lang:php -->
App::singleton('BillerInterface', 'StripBiller');

Master The Container 掌握容器

Want to learn even more about the container? Read through its source! The container is only one class: Illuminate\Container\Container. Read over the source code to gain a deeper understanding of how the container works under the hood.

想了解更多關於容器的知識? 去讀源碼!容器只有一個類Illuminate\Container\Container. 讀完了你就對容器有更深的認識了。

下一篇

相關文章
相關標籤/搜索