PHP重载以及Laravel门面Facade
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 "<pre>\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 | 在静态类调用一个不可访问方法时 |
例:(修改来自官方文档代码)
<?php
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 $name is 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中也可以这么做。
PHP重载以及Laravel门面Facade的更多相关文章
- Laravel开发:Laravel框架门面Facade源码分析
前言 这篇文章我们开始讲 laravel 框架中的门面 Facade,什么是门面呢?官方文档: Facades(读音:/fəˈsäd/ )为应用程序的服务容器中可用的类提供了一个「静态」接口.Lara ...
- laravel门面和服务提供者使用
关于laravel门面和服务提供者使用的一点见解,门面之词,不足之处,还请多多指教. 在laravel中,我们可能需要用到自己添加的类时,可以建立一个文件夹专门存放类文件,也可以使用laravel ...
- laravel门面与服务提供者区别
laravel门面模式与服务提供者区别 以 Laravel 自带的文件系统为例,在 config/app.php 的配置文件的 providers 数组中,注册了一个服务提供者: Illuminate ...
- 门面(Facade)模式
门面模式是对象的结构模式,外部与一个子系统的通信必须通过一个统一的门面对象进行.门面模式提供一个高层次的接口,使得子系统更易于使用. 医院的例子 现代的软件系统都是比较复杂的,设计师处理复杂系统的一个 ...
- 谈谈thinkphp5.1中容器(Container)和门面(Facade)的实现
tp5.1中引入了容器(Container)和门面(Facade)这两个新的类 官方文档已经给出了定义: 容器(Container)实现类的统一管理,确保对象实例的唯一性. 门面(Facade)为容器 ...
- 5.1中容器(Container)和门面(Facade)的实现
tp5.1中引入了容器(Container)和门面(Facade)这两个新的类 官方文档已经给出了定义: 容器(Container)实现类的统一管理,确保对象实例的唯一性. 门面(Facade)为容器 ...
- Laravel 门面实例教程 —— 创建自定义 Facades 类
我们首先创建一个需要绑定到服务容器的Test类: <?php namespace App\Facades; class Test { public function doSomething() ...
- laravel 门面的介绍和使用
#上文讲述了laravel中怎么用容器依赖注入类的示例.其实在服务提供者上面在封装一层静态调用,这就是门面.静态调用门面,返回了容器中注册的别名和实例. #下面是测试的示例 #先创建要操作的类 < ...
- laravel中facade serviceprovider的理解
一个serviceprovider就是一个解决某个功能的公用模块,实际上可以直接用在di里注册然后从di中取出,为啥还要搞个facade呢? 有几个方面的原因 1.把实例化移入到serviceprov ...
随机推荐
- wcf 中客户端调用之死 感悟 wcf与原来的webservice2.0 的客户端调用区别(wcf调用完不关闭的话那就把web服务搞死了)
说到wcf,本人也是刚刚使用所以不是很熟悉 在做项目的时候采用webservice+客户端程序架构 写了一个wcf中的webservice之后,又写了很多的客户端exe程序,有的是轮询调用这个webs ...
- 【MySQL】MySQL之MySQL常用的函数方法
MySQL常用函数 本篇主要总结了一些在使用MySQL数据库中常用的函数,本篇大部分都是以实例作为讲解,如果有什么建议或者意见欢迎前来打扰. limit Select * from table ord ...
- Swift 类
1.类概念 类是一种抽象的概念,它实际上并不存在于现实中的时间和空间里. 在定义一个类时,我们就会在类中定义该类事物的特性和行为,从术语上讲,特性叫类的属性,行为叫类的方法. 类是一个静态的概念,类本 ...
- windows开机后键盘失灵(非硬件原因)解决办法
今天来了,开机时突然发现输入密码时,键盘不管用了,试了一下键盘没问题,插口也没问题,能进入安全模式,很奇怪,昨天好好的今天却不能用了,找人倒腾了大半天也没搞出来,后来用PE盘消掉了密码,总算进入了系统 ...
- df -h和du -sh显示结果不一样的原因及解决
一.背景:一台2T硬盘的mysql服务器,保存电话的CDR信息.按照历史数据的水平,一个月能生成20+GB的文件.然而短短的半年时间,满了?! 登录服务器看谁占了这么大的空间?好吧,slow-quer ...
- .net自定义控件Control、WebControl、CompositeControl
一.呈现方法 1.Control主要有以下4个方法用于呈现 //该方法为入口方法 public virtual void RenderControl (HtmlTextWriter writer) { ...
- U811.1接口EAI系列之一--通用把XML传送给EAI处理方法--PowerBuilder语言
1.前面配置参考:http://www.cnblogs.com/spring_wang/p/3393147.html 2.pb通用调EAI方法代码如下: //===================== ...
- wifiphisher 钓鱼工具的使用
wifiphisher 钓鱼工具的使用一.简介 Wifiphisher是一个安全工具,具有安装快速.自动化搭建的优点,利用它搭建起来的网络钓鱼攻击WiFi可以轻松获得密码和其他凭证.与其它(网络钓鱼) ...
- C# .net WPF无边框移动窗体
转自 http://download.csdn.net/detail/xiang348352/3095084 WPF无边框移动窗体,先在<Window>里添加 MouseLeftButto ...
- Java数据结构和算法(十):二叉树
一.简介 二叉树是树这种数据结构的一员,后面我们还会介绍红黑树,2-3-4树等数据结构.那么为什么要使用树?它有什么优点? 前面我们介绍数组的数据结构,我们知道对于有序数组,查找很快,并介绍可以通过二 ...