在Support/Facades中的大部份類別,都是繼承此Facade類別、只實作getFacadeAccessor函式。
產生少打很多字的效果:developer只要呼叫facade類別的靜態函式,Laravel就會自動去對應到某個物件的某個方法。
當然了,不少工程師討厭這種特效,參見:讓你少打很多字:Facades。
那,這種特效又是如何做到的呢?
instance(static::getFacadeAccessor(), $instance);
}
/**
* Initiate a mock expectation on the facade.
*
* @param mixed
* @return \Mockery\Expectation
*/
public static function shouldReceive()
{
$name = static::getFacadeAccessor();
if (static::isMock())
{
$mock = static::$resolvedInstance[$name];
}
else
{
$mock = static::createFreshMockInstance($name);
}
return call_user_func_array(array($mock, 'shouldReceive'), func_get_args());
}
/**
* Create a fresh mock instance for the given class.
*
* @param string $name
* @return \Mockery\Expectation
*/
protected static function createFreshMockInstance($name)
{
static::$resolvedInstance[$name] = $mock = static::createMockByName($name);
if (isset(static::$app))
{
static::$app->instance($name, $mock);
}
return $mock;
}
/**
* Create a fresh mock instance for the given class.
*
* @param string $name
* @return \Mockery\Expectation
*/
protected static function createMockByName($name)
{
$class = static::getMockableClass($name);
return $class ? \Mockery::mock($class) : \Mockery::mock();
}
/**
* Determines whether a mock is set as the instance of the facade.
*
* @return bool
*/
protected static function isMock()
{
$name = static::getFacadeAccessor();
return isset(static::$resolvedInstance[$name]) && static::$resolvedInstance[$name] instanceof MockInterface;
}
/**
* Get the mockable class for the bound instance.
*
* @return string
*/
protected static function getMockableClass()
{
if ($root = static::getFacadeRoot()) return get_class($root);
}
/**
* Get the root object behind the facade.
*
* @return mixed
*/
public static function getFacadeRoot()
{
return static::resolveFacadeInstance(static::getFacadeAccessor());
}
/**
* Get the registered name of the component.
*
* @return string
*
* @throws \RuntimeException
*/
protected static function getFacadeAccessor()
{
throw new \RuntimeException("Facade does not implement getFacadeAccessor method.");
}
/**
* Resolve the facade root instance from the container.
*
* @param string $name
* @return mixed
*/
protected static function resolveFacadeInstance($name)
{
if (is_object($name)) return $name;
if (isset(static::$resolvedInstance[$name]))
{
return static::$resolvedInstance[$name];
}
return static::$resolvedInstance[$name] = static::$app[$name];
}
/**
* Clear a resolved facade instance.
*
* @param string $name
* @return void
*/
public static function clearResolvedInstance($name)
{
unset(static::$resolvedInstance[$name]);
}
/**
* Clear all of the resolved instances.
*
* @return void
*/
public static function clearResolvedInstances()
{
static::$resolvedInstance = array();
}
/**
* Get the application instance behind the facade.
*
* @return \Illuminate\Foundation\Application
*/
public static function getFacadeApplication()
{
return static::$app;
}
/**
* Set the application instance.
*
* @param \Illuminate\Foundation\Application $app
* @return void
*/
public static function setFacadeApplication($app)
{
static::$app = $app;
}
/**
* Handle dynamic, static calls to the object.
*
* @param string $method
* @param array $args
* @return mixed
*/
public static function __callStatic($method, $args)
{
$instance = static::getFacadeRoot();
switch (count($args))
{
case 0:
return $instance->$method();
case 1:
return $instance->$method($args[0]);
case 2:
return $instance->$method($args[0], $args[1]);
case 3:
return $instance->$method($args[0], $args[1], $args[2]);
case 4:
return $instance->$method($args[0], $args[1], $args[2], $args[3]);
default:
return call_user_func_array(array($instance, $method), $args);
}
}
}
最重要的函式只是這樣而已。使用PHP的magic method「__callStatic」,在類別呼叫靜態函式而找不到時,使用getFacadeRoot找到對應的物件,然後根據參數的數量去呼叫物件的方法。
注意這邊的設計:參數在4個以下都會直接呼叫方法,超過的話則用call_user_func_array呼叫方法。
這是因為call_user_func_array執行時有一點點慢的關係。