php5.1 facade,PHP重载以及Laravel门面Facade

本文详细介绍了PHP中的魔术方法,包括__set、__get、__isset、__unset和__callStatic等,以及它们在属性和方法重载中的应用。接着,文章探讨了Laravel中的Facade模式,解释了它如何利用PHP的__callStatic来实现静态方法调用业务类的功能,并提供了一个自定义Facade的简单示例。最后,提到了__invoke魔术方法及其在函数对象中的作用。
摘要由CSDN通过智能技术生成

[TOC]

Laravel提供了许多易用的Facade,让我们用起来特步顺手,那么这些Facade的原理是什么呢?

其实是使用了PHP的重载。

重载的概念

PHP所提供的"重载"(overloading)是指动态地"创建"类属性和方法。

在PHP里,是通过魔术方法(magic methods)来实现的。而在C++/Java里重载指的是,一个类中多个名字相同而参数类型列表不相同的方法。Lua中的元表,倒是和PHP的重载概念类似,对于学习过C++/Java的同学,可以把PHP中的重载当作新的概念即可,不必纠结为啥和C++/Java的不同。

魔术方法中的重载

在PHP中,魔术方法有很多,用于重载的有下面这些

属性重载

方法

作用

__set

赋值不可访问属性时

__get

读取不可访问属性时

__isset

对不可访问属性调用 isset() 或 empty() 时

__unset

对不可访问属性调用 unset() 时

如:(代码来自官方文档)

class PropertyTest {

/** 被重载的数据保存在此 */

private $data = array();

/** 重载不能被用在已经定义的属性 */

public $declared = 1;

/** 只有从类外部访问这个属性时,重载才会发生 */

private $hidden = 2;

public function __set($name, $value)

{

echo "Setting '$name' to '$value'\n";

$this->data[$name] = $value;

}

public function __get($name)

{

echo "Getting '$name'\n";

if (array_key_exists($name, $this->data)) {

return $this->data[$name];

}

$trace = debug_backtrace();

trigger_error(

'Undefined property via __get(): ' . $name .

' in ' . $trace[0]['file'] .

' on line ' . $trace[0]['line'],

E_USER_NOTICE);

return null;

}

/** PHP 5.1.0之后版本 */

public function __isset($name)

{

echo "Is '$name' set?\n";

return isset($this->data[$name]);

}

/** PHP 5.1.0之后版本 */

public function __unset($name)

{

echo "Unsetting '$name'\n";

unset($this->data[$name]);

}

/** 非魔术方法 */

public function getHidden()

{

return $this->hidden;

}

}

echo "

\n";

$obj = new PropertyTest;

$obj->a = 1;

echo $obj->a . "\n\n";

var_dump(isset($obj->a));

unset($obj->a);

var_dump(isset($obj->a));

echo "\n";

echo $obj->declared . "\n\n";

echo "Let's experiment with the private property named 'hidden':\n";

echo "Privates are visible inside the class, so __get() not used...\n";

echo $obj->getHidden() . "\n";

echo "Privates not visible outside of class, so __get() is used...\n";

echo $obj->hidden . "\n";

?>

以上输出Setting ‘a‘ to ‘1‘

Getting ‘a‘

1

Is ‘a‘ set?

bool(true)

Unsetting ‘a‘

Is ‘a‘ set?

bool(false)

1

Let‘s experiment with the private property named ‘hidden‘:

Privates are visible inside the class, so __get() not used...

2

Privates not visible outside of class, so __get() is used...

Getting ‘hidden‘

Notice: Undefined property via __get(): hidden in on line 70 in on line 29

注意只有当这个属性不存在时才被重载。

方法重载

方法

作用

__call

在对象中调用一个不可访问方法时

__callStatic

在静态类调用一个不可访问方法时

例:(修改来自官方文档代码)

class MethodTest

{

public function __call($name, $arguments)

{

// 注意: $name 的值区分大小写

echo "Calling object method '$name' "

. implode(', ', $arguments). "\n";

}

/** PHP 5.3.0之后版本 */

public static function __callStatic($name, $arguments)

{

// 注意: $name 的值区分大小写

echo "Calling static method '$name' "

. implode(', ', $arguments). "\n";

}

public function say()

{

echo "hello\n";

}

}

$obj = new MethodTest;

$obj->runTest('in object context');

MethodTest::runTest('in static context'); // PHP 5.3.0之后版本

?>

输出

Calling object method ‘runTest‘ in object context

Calling static method ‘runTest‘ in static context

注意当存在类方法时,静态调用是不会调用__callStatic的,如调用MethodTest::say();会报错

Strict Standards: Non-static method MethodTest::say() should not be called statically

Laravel中的Facade

在Laravel中,Facade模式可以直接方便的使用静态方法,来调用对应的业务类。实际上Facade就是利用了__callStatic特性。

让我们自己实现一个Facade。

1、Facade父类,主要是__callStatic 重载

abstract class Facade{

public static function getInstance(){

die("child class should implement getInstance");

}

public static function __callStatic($name, $arguments)

{

$instance = static::getInstance();

if(!$instance){

die("instance not init");

}

if(method_exists($instance,$name)){

$instance->$name(...$arguments);

// 或者 call_user_func_array([$instance,$name],$arguments);

}else{

echo "function$nameis not exist";

}

}

}

2、业务类,具体的实现,这里我们简单的输出一句话

class DemoService {

public function hello($name)

{

echo "hello$name\n";

}

}

3、调用的门面,继承Facade父类,实现getInstance即可

class Demo extends Facade{

public static function getInstance()

{

return new DemoService();

}

}

4、测试Demo::hello("world");,输出

hello world

当然在Laravel中稍微要复杂点,通过容器来动态获取业务类的实例。

public static function getFacadeRoot()

{

return static::resolveFacadeInstance(static::getFacadeAccessor());

}

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];

}

而这个$app 在框架启动时通过 Facade::setFacadeApplication($app);赋值,实际就是容器。

扩展 谈谈__invoke

魔术方法中另外一个很有趣的方法是__invoke,在C++中类似功能叫做函数对象(Function Object)。

示例:

class Add{

public function __invoke($a,$b)

{

return $a+$b;

}

}

$add = new Add();

echo $add(1,3);

函数对象有什么用呢?在C++中主要用来实现算法库STL,其实在PHP中也可以这么做。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值