为什么要使用引用?目的很简单,减少创建对象的副本,从而可以减少内存消耗。
但是,在PHP中,一些情况下却无法使用引用。典型的情况有:
1、通过__callStatic静态调用一个类的方法时。
为什么要这么做呢?这是因为,用此方法,可以减少大量的new。方便快速开发。
因为,在PHP中,我们new一个类以后,并没有也并不需要手工释放。
所以,我们经常通过__callStatic,在这个函数中实现新对象的创建。
比如:在Laravel项目的Repsitory中,一般我们是这么做的。
public function __callStatic($method,$parameters){ $instance = app(get_called_class()); return $instance->$method(...$parameters); }
但这就出现了问题,参数不能引用传参。
2、通过__call调用。与上述__callStatic是一样的。
3、通过call_user_func和call_user_func_array这两个函数调用。
4、把对象当函数使用,这就是说,函数是通过__invoke进行调用。
虽然,函数的参数不能用引用传参,并且只发生在这5个地点。但这也是相当致命的。因为这些,不我不得不在代码中创建变量的副本。从而浪费内存。
不仅如此,全世界的PHP程序员都在试图寻找这个问题的解决方案。但是,一直没有好的方法。
目前,网上提供的方法有:
在哪到参数后,这时,参数还是引用,所以,一般都是在这里做文章:
第一种方案:
把参数放到数组中,在数组内引用。
比如函数:
function test(&$foo){ return $foo; }
调用时:
call_user_func_array("test",[&$arg]);
但这个方法有些问题,一个参数好办,多个参数,第二个要引用则会如何?
没有办法。除非合并起来引用。
第二种方案:
因为,对象object参数永远是引用的,所以,直接把变量放到 stdclass中。
这时,函数中也不要定义引用了。
function test($foo){ return $foo->some; }
调用时:
$obj = new stdclass(); $obj->some = $foo; call_user_func_array("test",$obj);
这样有两个问题:第一,凭空多写两行代码。第二,定义方与调用方要约定好,参数放在stdclass的哪一个属性中。否则,就会找不到。
我们现在提供的方案则是一个相对比较好一些的方案。这一方案是使用PHP的另一语言特性:闭包。
代码如下:
if(!function_exists('byRef')){ /** * @desc 让参数强制引用的函数。通过闭包创建一个引用通道。 * @param $data * @return Closure */ function byRef(&$data){ //传入引用参数 return function &()use(&$data){ //定义闭包函数以引用返回,同时接收引用参数 return $data; }; } }
将以上代码,保存到helpers.php的文件中。
首先要加载此函数。当然,你可以使用include,require等语句。
但我相信,这年头,你连composer都没用上,对此需求不大。
那么,composer项目中,怎么配自动加载呢?
如果是composer项目,那么,在项目根目录中的composer.json文件中的"autoload"中添加:
"files": [ "app/Helpers/helpers.php" ],
注:上述路径则指明,你是将文件保存在app/Helpers/目录中的。
添加以后,这个全局函数就可以使用了。
接下来,我们说一下使用示例:
例如:我们要调用的源码是:
$ret = SomeRepository::SomeMethod($pass_data,$columns,$where,$order) ;
其中,我们想让 $data 为引用传参,只要这样:
$ret = SomeRepository::SomeMethod(byRef($pass_data),$columns,$where,$order) ;
同时,在类的 SomeMethod方法中要增加几行代码
public function SomeMethod(\Closure $data,$columns,$where,$order){ //以下这个代码不是必须的。因为,我们会直接用闭包方式获取数据。 if(!$data instanceof Closure){ //检测闭包的有效性。 Throw InvalidArgumentException("Data is not valid Closure."); } //只要这一行代码就够了。如果出错,证明调用方未使用强制引用函数。 $src_data = & $data(); //通过引用从闭包中获取数据 //下面,是你的代码。你直接修改$src_data,不用return,你会发现: //$pass_data在同步跟着你的代码改变。 }
以下代码是一个可以测试的示例:
function byRef(&$data){ return function &()use(&$data){ return $data; }; } function &test($try){ $try_data = &$try(); return $try_data; } $data = '123456'; $data_after = &test(byRef($data)); $data_after = '345678'; echo($data); //结果输出:345678
可以看出,通过闭包进行强制传参,代码是最简单,并且,使用也是最方便的。
相关推荐
【标题】:“PHP 5.0中多态性的实现方案” 【描述】:本文探讨了多态性在PHP 5.0中的实现及其在面向对象设计中的应用,同时分析了PHP 5中多态性的优缺点,特别是关于迟绑定的支持。 【标签】:“职场管理”(虽然...
总结起来,PHP的引用计数器和垃圾回收机制是其内存管理的核心组成部分,它们帮助PHP在动态语言中实现了高效的内存分配和回收。理解这些机制的工作原理,有助于编写出更加高效、内存友好的代码。
接口还可以用于强制执行某些类必须实现特定的方法,这对于设计模式,如策略模式或者工厂模式非常有用。 **接口的引用与规范**是另一个重要的主题。当一个类声明实现接口时,它必须实现接口中定义的所有方法,否则会...
在PHP 5.4中, Trait 的实现使得类间的方法复用变得更加灵活。此外,这个版本引入了Traits、匿名函数、简化的数组定义以及 Traits 的支持。同时,`__DIR__`和`__TRAIT__`魔术常量也被添加进来。你可以通过官方镜像...
6. **接口(Interface)和抽象类(Abstract Class)**:在多态场景下,接口和抽象类可以用来定义共同的行为,强制子类实现特定方法。虽然例子中没有涉及,但在实际开发中,这些概念非常关键。 理解并熟练运用这些...
在PHP开发基础培训中,我们将深入探讨PHP编程的关键概念,包括变量、常量、函数、对象、数组、字符串和其他核心特性。以下是对这些概念的详细解释: 1. 变量: - 变量是存储数据的容器。在PHP中,变量以美元符号 ...
在实际开发中,源码分析和工具的使用有助于理解这些转换如何在代码中实现。通过查看源码,我们可以了解编译器如何处理不同类型间的转换。同时,利用调试工具可以观察变量在转换过程中的具体变化,这有助于我们更好地...
继承允许一个类(子类)继承另一个类(父类)的属性和方法,而接口则定义了一组必须被实现的方法,提供了一种强制执行特定行为的方式。抽象类则作为其他类的基类,通常包含抽象方法,需要子类来具体实现。 总的来说...
在解压"php-7.0.2.tar.gz"后,你会得到一个名为"php-7.0.2"的目录,里面包含了PHP源代码的所有文件和子目录,如`ext`(扩展库)、`src`(源代码)、`Zend`(引擎实现)、`doc`(文档)等。开发者可以通过编译这些源...
通过接口,我们可以确保所有实现该接口的类都具有相同的方法,这在设计大型复杂系统时特别有用,因为它可以强制执行一致性。 **多态(Polymorphism)** 多态是面向对象的三大特性(封装、继承、多态)之一,它允许...
引用Nissan的Xterra的话来说就是PHP可以做到你想让它做到的一切而且无所不能! 1.3 竞争对手:ASP,mod_perl,JSP 我当然不清楚ASP/JSP能做些什么。不过明确的是编写那样的代码有多简单,购买它们会有多昂贵以及它们...
在IT行业中,PHP是一种广泛使用的服务器端脚本语言,尤其在Web开发领域有着重要的地位。腾讯推出的PHP基础培训教程旨在帮助初学者或开发者系统地掌握PHP编程基础。下面将详细阐述教程中的关键知识点: 1. **变量与...
数据类型转换在PHP中是非常灵活的,可以将一个类型强制转换为另一个类型。例如,`(boolean)`用于转换为布尔型,`(string)`用于转换为字符串型,`(integer)`用于转换为整型,`(float)`用于转换为浮点型,`(array)`...
此外,PHP7还新增了弱引用(Weak References),这在处理循环引用和大型对象图时非常有用,因为它们不会阻止垃圾回收器清理不再使用的对象。 在本书的源代码中,你可能会找到关于数据库操作、文件系统交互、网络...
在学习和使用PHP的过程中,我们通常默认PHP文件的后缀为.php。然而实际上,PHP文件并非必须以.php结尾,这一点对提高网站的安全性和灵活性有一定帮助。当PHP文件使用非.php后缀时,它不会被作为PHP脚本执行,而是被...
类可以使用 `implements` 关键字来引用接口,并实现接口中定义的所有抽象方法。例如: - **普通类引用接口** ```php class mypc implements demo, demo2, demo3 { // 实现接口中定义的所有方法 } ``` - **...
在PHP中,由于`SOAP`扩展本身不强制要求客户端提供特定的SOAP头,因此需要在服务端的方法内部进行检查。例如,`pc_authenticate_user`方法可以用来验证用户凭据。如果用户身份有效,方法返回`true`;否则,返回`...
在PHP中,重载方法是指在子类中覆盖父类的方法,以便提供不同的实现。这对于定制行为或改变默认行为非常有用。 例如: ```php class Animal { public function makeSound() { return 'Some sound'; } } class ...
这样的设计允许开发者定义一个接口,强制子类实现特定的方法。 二、接口(Interface) 接口是另一种实现多继承的方式,它定义了一组必须由实现该接口的类来实现的方法。在PHP中,使用`interface`关键字定义接口,类...