为什么要使用引用?目的很简单,减少创建对象的副本,从而可以减少内存消耗。
但是,在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
可以看出,通过闭包进行强制传参,代码是最简单,并且,使用也是最方便的。
相关推荐
17.2 PHP中Session的实现 280 17.2.1 开始使用Session 280 17.2.2 Session预定义数组 281 17.2.3 Session的检测与注销 281 17.2.4 PHP中Session处理的定制 282 17.3 Session应用实例——登录验证 286 17.3.1 数据库...
引用Nissan的Xterra的话来说就是PHP可以做到你想让它做到的一切而且无所不能! 1.3 竞争对手:ASP,mod_perl,JSP 我当然不清楚ASP/JSP能做些什么。不过明确的是编写那样的代码有多简单,购买它们会有多昂贵以及它们...
强制微信内打开的,还是很不错的,用来给小程序做引流简直太方便了。 以下引用原介绍: 可实现点击链接跳转到微信小程序,目前支持短信、邮件、百度、知乎、抖音、快手、QQ、微信、B站、今日头条、浏览器、自己...
laravel-cascade-deletes此Laravel / Lumen软件包为Laravel的Eloquent ORM提供了应用程序...例如,如果您正在使用SoftDeletes或使用多态关系,则在这些情况下,数据库中的外键无法强制引用完整性,因此应用程序需要介入
模块管理机制,方便的生成首页模块模板,只要正确的替换默认模板中的生成代码,既可实现若干新组合。 提供两种专辑排序功能,方便用户对视频较多的专辑进行整理。 在视频播放期间,可以收藏视频或者添加到自己的...
现在很多网站都有实现用户集。然而为了防止机器人的网络攻击。限制登陆或者注册是有必要的。 在注册和登陆时强制要求输入一个机器难以识别的字符串集是一个不错的选择。虽然不能解决根本问题,但至少可以增加他们的...
添加CKFinder集成演示修正:粘贴强制转文本模式下,换行丢失问题的修正(感谢luofei614提供修正方案)修正:修复IE9第二屏无法选择问题修正:修正不支持jQuery 1.9问题,需要引用jquery-migrate修正:修正width:'700'...
演示Address EJB的实现,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,用client的getHome()函数调用Home接口函数得到远程...
演示Address EJB的实现,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,用client的getHome()函数调用Home接口函数得到远程...
ExtAspNet v2.2.1 ExtAspNet是一组专业的Asp.net控件库,拥有原生的AJAX支持和丰富的UI效果, 目标是创建没有JavaScript,没有... -在Page_Load中设置了哪些需要在AJAX中更新的Asp.net控件会在回发时保持状态,可以...
-修正extjs最新版本(v3.2.2)中的一个bug,如果下拉列表中存在两个相同的Text,则SelectedValue返回值永远是第一个Text的值(feedback:ben.zhou)。 -应用补丁#6593, #6621(feedback:vbelyaev)。 +修正IE7下Grid分页...
1.修正:粘贴强制转文本模式下,换行丢失问题的修正(感谢luofei614提供修正方案) 2.修正:修复IE9第二屏无法选择问题 3.修正:修正不支持jQuery 1.9问题,需要引用jquery-migrate 4.修正:修正width:'700'参数...
在这一讲中,我们主要是了解一下 Linux 的概况,以及对 Linux 有一个初步的感性认识。 一.什么是Linux? Linux 是一个以 Intel 系列 CPU(CYRIX,AMD 的 CPU也可以)为硬件平台,完全免费的 UNIX 兼容系统,完全...