官方文档 在一方面真的写的很糟糕,完全没描述相互之间的关系。

事实上, 服务提供者(Service Provider) 、 服务容器(Service Container) 、 Contracts 、 Facades 是一件东西的多个方面。其实就是 Yii 的组件(Component)。

和 Yii 一样,Laravel 的所有功能都是通过与 Yii 组件类似的服务架构来实现的。

一个最简单直接的例子是 Lavarel Hashing 服务。其自身只是一个 Bcrypt hash 的封装。

首先,Laravel 5 定义了一个 Contracts: Illuminate/Contracts/Hashing/Hasher.php

<?php namespace Illuminate\Contracts\Hashing;
interface Hasher {
	/**
	 * Hash the given value.
	 *
	 * @param  string  $value
	 * @param  array   $options
	 * @return string
	 */
	public function make($value, array $options = array());
	/**
	 * Check the given plain value against a hash.
	 *
	 * @param  string  $value
	 * @param  string  $hashedValue
	 * @param  array   $options
	 * @return bool
	 */
	public function check($value, $hashedValue, array $options = array());
	/**
	 * Check if the given hash has been hashed using the given options.
	 *
	 * @param  string  $hashedValue
	 * @param  array   $options
	 * @return bool
	 */
	public function needsRehash($hashedValue, array $options = array());
}

Contracts 只是描述一个服务的具体方法,而不是实现该服务。Container 才是服务的具体实现,对于一个服务来说,可能会有多种不同的实现。Hash 目前只有一个,就是: Illuminate/Hashing/BcryptHasher.php

<?php namespace Illuminate\Hashing;
use RuntimeException;
use Illuminate\Contracts\Hashing\Hasher as HasherContract;
class BcryptHasher implements HasherContract {
	/**
	 * Default crypt cost factor.
	 *
	 * @var int
	 */
	protected $rounds = 10;
	/**
	 * Hash the given value.
	 *
	 * @param  string  $value
	 * @param  array   $options
	 * @return string
	 *
	 * @throws \RuntimeException
	 */
	public function make($value, array $options = array())
	{
		$cost = isset($options['rounds']) ? $options['rounds'] : $this->rounds;
		$hash = password_hash($value, PASSWORD_BCRYPT, array('cost' => $cost));
		if ($hash === false)
		{
			throw new RuntimeException("Bcrypt hashing not supported.");
		}
		return $hash;
	}
	/**
	 * Check the given plain value against a hash.
	 *
	 * @param  string  $value
	 * @param  string  $hashedValue
	 * @param  array   $options
	 * @return bool
	 */
	public function check($value, $hashedValue, array $options = array())
	{
		return password_verify($value, $hashedValue);
	}
	/**
	 * Check if the given hash has been hashed using the given options.
	 *
	 * @param  string  $hashedValue
	 * @param  array   $options
	 * @return bool
	 */
	public function needsRehash($hashedValue, array $options = array())
	{
		$cost = isset($options['rounds']) ? $options['rounds'] : $this->rounds;
		return password_needs_rehash($hashedValue, PASSWORD_BCRYPT, array('cost' => $cost));
	}
	/**
	 * Set the default password work factor.
	 *
	 * @param  int  $rounds
	 * @return $this
	 */
	public function setRounds($rounds)
	{
		$this->rounds = (int) $rounds;
		return $this;
	}
}

除了实现 Contracts 中定义的三个方法外,还实现了一个额外 setRounds() 方法。

下一步就是注册为服务提供者了: Illuminate/Hashing/HashServiceProvider.php

<?php namespace Illuminate\Hashing;
use Illuminate\Support\ServiceProvider;
class HashServiceProvider extends ServiceProvider {
	/**
	 * Indicates if loading of the provider is deferred.
	 *
	 * @var bool
	 */
	protected $defer = true;
	/**
	 * Register the service provider.
	 *
	 * @return void
	 */
	public function register()
	{
		$this->app->singleton('hash', function() { return new BcryptHasher; });
	}
	/**
	 * Get the services provided by the provider.
	 *
	 * @return array
	 */
	public function provides()
	{
		return array('hash');
	}
}

很明显的 register 了服务,具体做的就是 new 了一个 Container。如果容器有多种实现,这时建议使用 Config 来配置服务了。

$this->app->singleton('hash', function($app) { return new Hasher($app['config']['hash']); });

这时候 Hasher 实际上一个工厂类(Factory),使用配置来确定具体的,如 new Hasher('bcrypt') 来实例化。

如果服务要延迟载入,也就是按需载入。需要有一个激活标志,也就是 provides() 方法。

当然, HashServiceProvider.php 必须在 config/app.php 的 providers 中定义'Illuminate\Hashing\HashServiceProvider' 行。

这时,就可以使用:

$this->app->make('hash')->make('password');
$this->app['hash']->make('password');

最后,声明一个 Facade: Illuminate/Support/Facades/Hash.php

<?php namespace Illuminate\Support\Facades;
/**
 * @see \Illuminate\Hashing\BcryptHasher
 */
class Hash extends Facade {
	/**
	 * Get the registered name of the component.
	 *
	 * @return string
	 */
	protected static function getFacadeAccessor()
	{
		return 'hash';
	}
}

在 config/app.php 的 aliases 中定义 'Hash' => 'Illuminate\Support\Facades\Hash' 行。

那么,就不用上面长长的 $this->app->make('hash') ,直接:

Hash::make('password');
转自:http://ju.outofmemory.cn/entry/144667

Logo

开源、云原生的融合云平台

更多推荐