`

PHP函数式编程的特性研究

    博客分类:
 
阅读更多
PHP不是像Lisp那样的函数式编程语言,更多的,PHP适合用C的风格来编写代码 
PHP中没有“函数”这种类型,也就是说,函数不能直接用变量来传递 
比如下面的代码
Php代码function test() {   
1.       echo "Just A Test!!!";   
2.   }   
3.   $test1=test;   
4.   echo gettype($test1);//输出string  

PHP是这样解析上面的代码的
Php代码  
1.   //出现一个裸字符串,不以$符开头,那么就把它当成常量   
2.   $test1=test;//PHP将test当成一个常量,但代码中并没有test这一常量,接着PHP将常量名当成其值   
3.   //当PHP遇到一个未定义常量时,就将它当成一个字符串值,如下   
4.     
5.   var_dump(UNDEFINED_CONSTANT);//将输出string(18) "UNDEFINED_CONSTANT"  

这表明PHP中的函数名在非调用的情况下(后面没有括号)会被当成一个字符串。 
而正巧PHP中有通过一个字符串名称动态调用一个函数的方法:
Php代码  
1.   $phpInfo='phpinfo';   
2.   $phpInfo();   
3.   //还有另外一种方式   
4.   call_user_func('phpinfo');  


在C语言中可以通过指向函数的指针来将函数作为参数传递以实现高级的FP, 
而在PHP中,则是通过将函数名称作为字符串传递,通过$fname()来调用 
($fname是一个字符串类型的变量,其值为函数名),或者通过call_user_func来调用 

那么到这里时就会发现PHP中函数的实现所带来的不便,因为函数是通过 
字符串来传递和调用的,那么就要求不能有函数名称相同的两个不同函数的存在 
即,PHP中的所有的函数(这里所说的“函数”不包括方法)都是全局函数, 
并且不允许在运行时重定义,因为如果允许重复定义函数(比如像大家熟悉的JavaScript那样), 
下面的代码就会出错
Php代码  
1.   //第一次定义test1函数   
2.   function test1() {   
3.       return 123;   
4.   }   
5.     
6.   //将变量$testFunction赋值为test1的函数名称   
7.   //事实上这种写法较低效,这样写更好一些:$testFunction='test1';   
8.   $testFunction=test1;   
9.     
10. //.......若干行代码之后   
11. //重新定义了test1   
12. function test1() {   
13.     return 456;   
14. }   
15.   
16. //输出与期望值不一样了,因为变量里只是保存的函数名而已   
17. //而并不是真正的对函数的引用   
18. echo $testFunction();  
 
 
 
 


既然PHP中所有函数都是全局函数,那么函数声明就自然不能 
嵌套着写了(指Closure),在讨论PHP中的Closure与Lambda之前 
先讨论一下PHP中的方法(即已经绑定到指定对象或类上的函数) 
先创建一个简单的类,将其静态方法直接输出看看是什么内容
Php代码  
1.   class Demo {   
2.       public static function test() {   
3.           return 123;   
4.       }   
5.   }   
6.     
7.   var_dump(Demo::test);//到这一步出错了   
8.   //因为PHP在解析Demo::test时,会将其看成是对Demo类的静态属性的读取   
9.   //而这个静态属性又不以$开头,那么就将其看成静态常量(const)   
10. //不存在这个常量,就出错了  
 


那么如果要动态的调用一个类(或实例)的方法该怎么办呢? 
先上一个现实中的例子,一个非常简单的Controller(当然真正的控制器不能这样简单)
Php代码  
1.   class Controller {   
2.       public function login() {   
3.           echo "Login";   
4.       }   
5.       public function home() {   
6.           echo "Home";   
7.       }   
8.       public function logout() {   
9.           echo "Logout!!!";   
10.     }   
11. }   
12. $action=$_GET['action'];//要调用的方法名称在action参数里面   
13. //接着要动态调用指定的方法   
14. Controller::$action();//使用这种方法,这主要得益于PHP的“变量的变量”机制   
15. //当然,要先检查一下类有没有这个方法,可以用PHP的反射机制检测   
16. $reflectionClass=new ReflectionClass('Controller');   
17. $reflectionClass->hasMethod($action);//测试一个是否有对应的方法   
18. //以及测试一下方法是否是静态方法   
19. $reflectionMethod=$reflectionClass->getMethod($action);   
20. $reflectionMethod->isStatic();//是静态方法则返回true  
 

除了使用PHP的可变变量机制外,还可以使用之前的call_user_func函数
Php代码  
1.   //传一个数组作为第一个参数,数组中第一个元素为类名,第二个元素为静态方法名称   
2.   call_user_func(array('Controller',$action));   
3.   //如果要向方法或函数传递参数,可以将参数附在后面   
4.   function test($a,$b) {   
5.       echo $a+$b;   
6.   }   
7.   call_user_func('test',123,456);   
8.   //或者在传不定参数时,使用call_user_func_array函数   
9.   call_user_func_array('test',array(123,456));   
10.   
11. //在PHP 4.1之前存在call_user_method函数及   
12. //call_user_method_array专门用来调用对象的方法,但现在废弃不用了  
 
如果需要调用实例的方法的话,则为
Php代码  
1.   class Demo {   
2.       public function test() {   
3.           echo "Instance Method";   
4.       }   
5.   }   
6.   $d=new Demo();   
7.     
8.   $d->$action();   
9.   //或者以这种方式调用   
10. call_user_func(array($d,$action));   
11. //如果类Demo没有将构造函数声明为私有的话,还仍然可以无需实例就调用实例方法   
12. call_user_func(array('Demo',$action));  

从上面的代码可以看得出来,PHP中的类也是以字符串形式的名称传递的 
像下在的代码
Php代码  
1.   $class=Demo;   
2.   echo gettype($class);//string   
3.   //原因和函数一样,PHP将Demo当成一个普通的裸字符串了  

到了PHP 5.2.3时,PHP中调用类的静态方法还有另外一种语法
Php代码  
1.   //PHP 5.2.3   
2.   call_user_func('Demo::'.$action);  

到了PHP 5.3开始,PHP引入了命名空间的概念,因此上面的调用将变成
Php代码  
1.   call_user_func(__NAMESPACE__.'::Demo::'.$action);  

看到上面的代码,其实可以猜想,类的静态方法不就是加了一个命名空间前缀的函数嘛 
(当然执行上下文及作用域不一样了) 
----------------------华丽的分隔线------------------------------ 
PHP中的Lambda及Closure 
在PHP 5.3之前,PHP中实现Lambda的语法非常别扭 
要将函数中的代码作为字符串传递给create_function方法去构造
Php代码  
1.   $lambda=create_function('$a','return addslashes(trim($a));');   
2.   //相当于构造这样一个函数   
3.   function lambda1($a) {   
4.       return addslashes(trim($a));   
5.   }  

这种对Lambda的支持真是鸡肋得很,用起来反而降低了效率 
将代码写到字符串中很容易出错 
这种风格的lambda创建方式只适用于非常简短的函数表达式 
那再看看上面的$lambda变量中保存的什么
Php代码  
1.   var_dump($lambda);   
2.   //仍然是字符串类型,并且命名特点为"lambda_"加一个数字   
3.   //后面的数字为PHP系统全局计数器,保证运行不会重复  

事实上用create_function创建的仍然是全局函数,只是这个全局函数的名字不会被猜到而已 
可能我们会尝试创建这样命名的函数
Php代码  
1.   function lambda_1() {   
2.       retunr 'Lambda!!!';   
3.   }   
4.   $lambda=create_function('','return 123;');   
5.   //如果你的PHP是系统启动后第一次运行,那么$lambda里面的字符串看起来就和lambda_1一样   
6.   //但执行代码调仍然一点没有错误   
7.   echo $lambda();//返回123;   
8.   echo lambda_1();//返回'Lambda!!!'  

其实,create_function生成的函数名有些特殊,它是NULL字符加上"lambda_"再加个一个数字标识 
而NULL字符我们是没有办法在声明函数时使用这个字符的,因此上面的代码不会冲突 
可以用下面的代码测试了看下
Php代码  
1.   $lambda=create_function('','return 123;');   
2.   preg_match('|\d+|',$lambda,$matches);//匹配出lambda数字标识   
3.   //通lambda数字编号来调用些函数表达式   
4.   call_user_func("\x00lambda_{$matches[0]}");//在字符串前面加个NULL字符   
5.   //始终输出123  

使用create_function不但写起来别扭,而且create_function方法只能创建一般的临时函数而已 
并不能实现闭包(虽然如果只是读取些标量的话可以变通一下实现,如下)
Php代码  
1.   function outer() {   
2.       $a=123;   
3.       return create_function('$a='.$a,'return $a;');   
4.   }   
5.   $inner=outer();   
6.   echo $inner();   
7.   //PHP有个很不爽的地主就是不把函数调用当成表达式,这种代码会出错   
8.   //outer()();或getRow()[0];  

而到了PHP 5.3,PHP开始支持真正的闭包,而且lambda更好使了,接近于JavaScript
Php代码  
1.   #!/usr/bin/php-5.3.0/php   
2.     
3.     
4.   $data=range(0,10);   
5.   //更接近于JavaScript的lambda语法   
6.   $newData=array_map(function ($v) {   
7.       $a=range(0,$v);   
8.       return array_sum($a);   
9.   },$data);   
10.   
11. function outer() {   
12.     $a=123;   
13.     //语法上生疏些,需要将要在lambda中访问的闭包变量列在use列表中   
14.     return function () use($a) {//闭包   
15.         echo $a;   
16.     };   
17. }   
18. $inner=outer();//只是不爽的地方就是,仍然不能这样写outer()();   
19. $inner();   
20. print_r($newData);   
21.   
22. //PHP也提供了像Lisp中的map,reduce,walk方法用于函数式编程   
23. //下面的代码用于将$_REQUEST中的每一个值进行trim   
24. array_walk('trim',$_REQUEST);  
 
PHP闭包中变量引用的问题 
…… 
如下面回复所提到的,下面的代码工作起来和想像中有些差距
Php代码  
1.   function outer() {   
2.       $a=0;   
3.       return function () use($a) {   
4.           return $a++;   
5.       };   
6.   }   
7.   $inner=outer();   
8.   echo $inner();//outputs 0   
9.   echo $inner();//outputs 0   
10. echo $inner();//outputs 0  

因为PHP中的闭包,只是对原变量中值进行拷贝而已,也就是说,use中列出来的变量,在运行时 
都是闭包函数中的局部变量,而并不是函数外面的变量
Php代码  
1.   function outer() {   
2.       $a=0;   
3.       return function () use($a) {//大致相当于有这样一个步骤:lambda1::$a=outer::$a   
4.           return $a++;   
5.       };   
6.   }  

如果要达到想像中的状态的话,只要在变量前加个按引用传值标识就行了
Php代码  
1.   function outer() {   
2.       $a=0;   
3.       return function () use(&$a) {   
4.           return $a++;   
5.       };   
6.   }   
7.   $inner=outer();   
8.   echo $inner();//0   
9.   echo $inner();//1   
10. echo $inner();//2   
11. echo $inner();//3  
 
作者:不详 来源:网络
分享到:
评论

相关推荐

    Elixir(函数式编程语言软件)v1.5官方免费正式版

    Elixir是一款免费的函数式编程语言,采用一种动态语言,灵活的语法和宏支持,建立在Erlang虚拟机之上,来构建并发、分布式、容错应用程序及热代码升级。软件功能强大,界面简洁,是您进行函数式编程的首选,需要的...

    pramda:PHP中的实用函数式编程

    PHP中的实用函数式编程 PS 1:自动管理的功能 PS 2:懒惰评估内置 PS 3:有趣(常用)使用 ELI5:什么是函数式编程,为什么要关注? 您正在从事的工作是否有可能以其他方式完成? 事实证明是可以的,并且它可以通过...

    php函数式编程简单示例

    主要介绍了php函数式编程,结合简单实例形式分析了php函数式编程相关实现方法及数组排序、闭包操作使用技巧,需要的朋友可以参考下

    lambda.php:PHP 函数式编程

    拉姆达.php lambda.php从面向对象的角度介绍了函数式编程。 您将看到的 PHP 代码实际上有效,但并不打算成为可靠的 PHP 扩展(还没有?)。 在 Linux 下,运行包含您的代码的php lambda.php 。 如果您想从面向对象的...

    不用静态类型函数式编程语言的十大理由

    你厌烦函数式编程么?我也烦,我真想呼吁那些想我一样明智的人远离这种语言。  这里要澄清一点,我指的这种静态类型函数式编程语言,包括那种类型推断或者静态缺省等等。实际上,是Haskell和ML—family(包括...

    PHP函数库,PHP函数大全,PHP函数实例,PHP函数手册,PHP5函数库实例

    PHP函数库,PHP函数大全,PHP函数实例,PHP函数手册,PHP5函数库实例 PHP函数库,PHP函数大全,PHP函数实例,PHP函数手册,PHP5函数库实例 curl获取远程文件内容 GD显示中文 PHP GIF动画生成类 PHP HTML转UBB函数 PHP ...

    functional-programming-php:使用php实现函数式编程方法

    使用PHP实现函数式编程 纯PHP Laravel收藏

    PHP脚本编程中的文件系统函数库

    PHP脚本编程中的文件系统函数库PHP脚本编程中的文件系统函数库

    php4中文函数手册

    PHP手册 ...BUG/建议 ------------------------------------------------...GNU gettext函数库 程式执行函数库 YP/NIS函数库 HTTP函数库 Pspell函数库 压缩函数库 ICAP函数库 GNU Readline函数库 PHP4新增的部份语法

    PHP函数集 PHP手册

    Apache特定函数库 图形函数库 GNU记录函数库 数组函数库 IMAP,POP3和...GNU gettext函数库 程式执行函数库 YP/NIS函数库 HTTP函数库 Pspell函数库 压缩函数库 ICAP函数库 GNU Readline函数库 PHP4新增的部份语法

    PHP笔记PHP 函数

    PHP笔记PHP 函数

    functional:函数式编程帮助器函数和类

    函数式编程帮助器函数和类 Ancarda \ Functional(也称为“ FP Kit ”)是PHP 7.0+的帮助器函数和类的集合,它使基本的Functional Programming更加容易。 Operation类允许以比一系列array_*函数更直观,更易理解的...

    PHP函数速查效率手册 source code

    脑动力:PHP函数速查效率手册 source code 张建辉 主编 电子工业出版社  PHP是现在最流行的网站开发技术。PHP提供的内部函数功能强大,解决常见的各种PHP问题。但是PHP函数繁杂,参数众多,造成大家学习和使用的...

    PHP编程网络大讲堂

    本书全面介绍PHP编程知识,全书共分4篇16章,内容包括:PHP基础入门篇(第1~4章),介绍PHP环境的搭建、PHP配置文件和指令、数据类型和流程控制语句,以及PHP下进行面向对象编程等知识;PHP数据处理篇(第5~10章)...

    php权威编程

    PHP 5首席设计师Andi Gutmans,PEAR创始人Stig Saether Bakken,PHP核心贡献者Derick Rethans三大高手合力而作:本书几乎囊括了PHP 5所有的新特性,包括PHP 5所有的新功能,PHP 5的面向对象编程方法和设计模式,以及...

    PHP常用函数手册 PHP函数

    PHP常用函数手册,Word版的。包括常用数学函数、字符/字串处理函数以及图像函数等

    PHP函数实验报告

    php实验用的文档,是对所学php课程的巩固,里面有不骤和代码

    php函数手册-比较全的php函数手册

    php函数手册-比较全的php函数手册,php学习必备参考手册

    编程函数查询小助手-易语言等等的编程函数查询小助手

    编程函数查询小助手-易语言等等的编程函数查询小助手编程函数查询小助手-易语言等等的编程函数查询小助手编程函数查询小助手-易语言等等的编程函数查询小助手编程函数查询小助手-易语言等等的编程函数查询小助手编程...

Global site tag (gtag.js) - Google Analytics