`
bardo
  • 浏览: 378141 次
  • 性别: Icon_minigender_1
  • 来自: 上海
博客专栏
D1407912-ab64-3e76-ae37-b31aa4afa398
浅述PHP设计模式
浏览量:11799
9d6df9f7-91da-3787-a37c-0e826525dd5d
Zend Framewor...
浏览量:10110
85b628bd-a2ed-3de2-a4b1-0d34985ae8b6
PHP的IDE(集成开发环...
浏览量:9495
社区版块
存档分类
最新评论

PHP中强制引用的实现

    博客分类:
  • PHP
阅读更多

 

  为什么要使用引用?目的很简单,减少创建对象的副本,从而可以减少内存消耗。

但是,在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.0中的实现及其在面向对象设计中的应用,同时分析了PHP 5中多态性的优缺点,特别是关于迟绑定的支持。 【标签】:“职场管理”(虽然...

    Php引用计时器和垃圾回收机制.pdf

    总结起来,PHP的引用计数器和垃圾回收机制是其内存管理的核心组成部分,它们帮助PHP在动态语言中实现了高效的内存分配和回收。理解这些机制的工作原理,有助于编写出更加高效、内存友好的代码。

    (第23讲) PHP面向对象开发的学习(七)

    接口还可以用于强制执行某些类必须实现特定的方法,这对于设计模式,如策略模式或者工厂模式非常有用。 **接口的引用与规范**是另一个重要的主题。当一个类声明实现接口时,它必须实现接口中定义的所有方法,否则会...

    php各版本下载地址.doc

    在PHP 5.4中, Trait 的实现使得类间的方法复用变得更加灵活。此外,这个版本引入了Traits、匿名函数、简化的数组定义以及 Traits 的支持。同时,`__DIR__`和`__TRAIT__`魔术常量也被添加进来。你可以通过官方镜像...

    PHP调用其他文件中的类

    6. **接口(Interface)和抽象类(Abstract Class)**:在多态场景下,接口和抽象类可以用来定义共同的行为,强制子类实现特定方法。虽然例子中没有涉及,但在实际开发中,这些概念非常关键。 理解并熟练运用这些...

    PHP开发基础培训 中文版 PPT

    在PHP开发基础培训中,我们将深入探讨PHP编程的关键概念,包括变量、常量、函数、对象、数组、字符串和其他核心特性。以下是对这些概念的详细解释: 1. 变量: - 变量是存储数据的容器。在PHP中,变量以美元符号 ...

    实例022 - 自动类型转换与强制类型转换

    在实际开发中,源码分析和工具的使用有助于理解这些转换如何在代码中实现。通过查看源码,我们可以了解编译器如何处理不同类型间的转换。同时,利用调试工具可以观察变量在转换过程中的具体变化,这有助于我们更好地...

    PHP的类、对象、构造方法。

    继承允许一个类(子类)继承另一个类(父类)的属性和方法,而接口则定义了一组必须被实现的方法,提供了一种强制执行特定行为的方式。抽象类则作为其他类的基类,通常包含抽象方法,需要子类来具体实现。 总的来说...

    php-7.0.2.tar.gz

    在解压"php-7.0.2.tar.gz"后,你会得到一个名为"php-7.0.2"的目录,里面包含了PHP源代码的所有文件和子目录,如`ext`(扩展库)、`src`(源代码)、`Zend`(引擎实现)、`doc`(文档)等。开发者可以通过编译这些源...

    PHP5面向对象开发教程第四章-PHP5接口与多态

    通过接口,我们可以确保所有实现该接口的类都具有相同的方法,这在设计大型复杂系统时特别有用,因为它可以强制执行一致性。 **多态(Polymorphism)** 多态是面向对象的三大特性(封装、继承、多态)之一,它允许...

    PHP基础教程 是一个比较有价值的PHP新手教程!

    引用Nissan的Xterra的话来说就是PHP可以做到你想让它做到的一切而且无所不能! 1.3 竞争对手:ASP,mod_perl,JSP 我当然不清楚ASP/JSP能做些什么。不过明确的是编写那样的代码有多简单,购买它们会有多昂贵以及它们...

    腾讯开发PHP基础培训教程

    在IT行业中,PHP是一种广泛使用的服务器端脚本语言,尤其在Web开发领域有着重要的地位。腾讯推出的PHP基础培训教程旨在帮助初学者或开发者系统地掌握PHP编程基础。下面将详细阐述教程中的关键知识点: 1. **变量与...

    PHP 程序常用笔记

    数据类型转换在PHP中是非常灵活的,可以将一个类型强制转换为另一个类型。例如,`(boolean)`用于转换为布尔型,`(string)`用于转换为字符串型,`(integer)`用于转换为整型,`(float)`用于转换为浮点型,`(array)`...

    《PHP7从入门到精通》全部案例源代码

    此外,PHP7还新增了弱引用(Weak References),这在处理循环引用和大型对象图时非常有用,因为它们不会阻止垃圾回收器清理不再使用的对象。 在本书的源代码中,你可能会找到关于数据库操作、文件系统交互、网络...

    PHP文件后缀不强制为.php方法

    在学习和使用PHP的过程中,我们通常默认PHP文件的后缀为.php。然而实际上,PHP文件并非必须以.php结尾,这一点对提高网站的安全性和灵活性有一定帮助。当PHP文件使用非.php后缀时,它不会被作为PHP脚本执行,而是被...

    php接口与接口引用的深入解析

    类可以使用 `implements` 关键字来引用接口,并实现接口中定义的所有抽象方法。例如: - **普通类引用接口** ```php class mypc implements demo, demo2, demo3 { // 实现接口中定义的所有方法 } ``` - **...

    PHP Cookbook读书笔记 – 第15章创建Web服务.docx

    在PHP中,由于`SOAP`扩展本身不强制要求客户端提供特定的SOAP头,因此需要在服务端的方法内部进行检查。例如,`pc_authenticate_user`方法可以用来验证用户凭据。如果用户身份有效,方法返回`true`;否则,返回`...

    php5面向对象

    在PHP中,重载方法是指在子类中覆盖父类的方法,以便提供不同的实现。这对于定制行为或改变默认行为非常有用。 例如: ```php class Animal { public function makeSound() { return 'Some sound'; } } class ...

    PHP5面向对象开发教程第三章-PHP5面向对象高级类特性

    这样的设计允许开发者定义一个接口,强制子类实现特定的方法。 二、接口(Interface) 接口是另一种实现多继承的方式,它定义了一组必须由实现该接口的类来实现的方法。在PHP中,使用`interface`关键字定义接口,类...

Global site tag (gtag.js) - Google Analytics