How to use functional programming in PHP_PHP Tutorial

WBOY
Release: 2016-07-13 10:33:36
Original
748 people have browsed it

PHP is not a functional programming language like Lisp. More importantly, PHP is suitable for writing code in C style. There is no such type of "function" in PHP, that is to say, functions cannot be passed directly using variables. For example, the following code:

function test() {
  echo "welcome to bkjia.com";
}

$test1 = test;
echo gettype($test1);
//输出string
Copy after login

This is how PHP parses the above code.

//出现一个裸字符串,不以$符开头,那么就把它当成常量  
//PHP将test当成一个常量,但代码中并没有test这一常量,接着PHP将常量名当成其值  
$test1 = test;
//当PHP遇到一个未定义常量时,就将它当成一个字符串值,如下  
var_dump(UNDEFINED_CONSTANT);
//将输出string(18) "UNDEFINED_CONSTANT"  
Copy after login

This indicates that the function name in PHP will be treated as a string when it is not called (without parentheses after it).

And it just so happens that there is a method in PHP to dynamically call a function through a string name:

$phpInfo = 'phpinfo';  
$phpInfo();  

//还有另外一种方式  
call_user_func('phpinfo');
Copy after login

In C language, functions can be passed as parameters through pointers to functions to implement advanced FP, while in PHP, function names are passed as strings and called through $fname() ($fname is a string type variable whose value is the function name), or called through call_user_func. Then when you get here, you will find the inconvenience caused by the implementation of functions in PHP. Because functions are passed and called through strings, it is required that there cannot be two different functions with the same function name. That is, all functions in PHP (the "functions" mentioned here do not include methods) are global functions, and are not allowed to be redefined at runtime, because if functions are allowed to be repeatedly defined (such as the familiar JavaScript), The following code will cause an error:

//第一次定义test1函数  
function test1() {  
    return 123;  
}  
  
//将变量$testFunction赋值为test1的函数名称  
//事实上这种写法较低效,这样写更好一些:$testFunction='test1';  
$testFunction=test1;  
  
//.......若干行代码之后  
//重新定义了test1  
function test1() {  
    return 456;  
}  
  
//输出与期望值不一样了,因为变量里只是保存的函数名而已  
//而并不是真正的对函数的引用  
echo $testFunction();
Copy after login

Since all functions in PHP are global functions, function declarations cannot be written nested (referring to Closure). Before discussing Closure and Lambda in PHP, let’s discuss the methods in PHP (that is, bound to a function on a specified object or class). First create a simple class and directly output its static methods to see what the content is.

class Demo {  
    public static function test() {  
        return 123;  
    }  
}  
var_dump(Demo::test);//到这一步出错了  
//因为PHP在解析Demo::test时,会将其看成是对Demo类的静态属性的读取  
//而这个静态属性又不以$开头,那么就将其看成静态常量(const)  
//不存在这个常量,就出错了 
Copy after login

So what should you do if you want to dynamically call a method of a class (or instance)? Let’s start with a real-life example, a very simple Controller (of course a real controller cannot be this simple)

class Controller {  
    public function login() {  
        echo "Login";  
    }  
    public function home() {  
        echo "Home";  
    }  
    public function logout() {  
        echo "Logout!!!";  
    }  
}  
$action=$_GET['action'];//要调用的方法名称在action参数里面  
//接着要动态调用指定的方法  
Controller::$action();//使用这种方法,这主要得益于PHP的“变量的变量”机制  
//当然,要先检查一下类有没有这个方法,可以用PHP的反射机制检测  
$reflectionClass=new ReflectionClass('Controller');  
$reflectionClass->hasMethod($action);//测试一个是否有对应的方法  
//以及测试一下方法是否是静态方法  
$reflectionMethod=$reflectionClass->getMethod($action);  
$reflectionMethod->isStatic();//是静态方法则返回true  
Copy after login

In addition to using PHP’s variable variable mechanism, you can also use the previous call_user_func function.

//传一个数组作为第一个参数,数组中第一个元素为类名,第二个元素为静态方法名称  
call_user_func(array('Controller',$action));  
//如果要向方法或函数传递参数,可以将参数附在后面  
function test($a,$b) {  
    echo $a+$b;  
}  
call_user_func('test',123,456);  
//或者在传不定参数时,使用call_user_func_array函数  
call_user_func_array('test',array(123,456));  
  
//在PHP 4.1之前存在call_user_method函数及  
//call_user_method_array专门用来调用对象的方法,但现在废弃不用了  
Copy after login

If you need to call the instance method,

class Demo {  
    public function test() {  
        echo "Instance Method";  
    }  
}  
$d=new Demo();  
  
$d->$action();  
//或者以这种方式调用  
call_user_func(array($d,$action));  
//如果类Demo没有将构造函数声明为私有的话,还仍然可以无需实例就调用实例方法  
call_user_func(array('Demo',$action));  
Copy after login

As can be seen from the above code, classes in PHP are also passed as string names. Like the following code:

$class=Demo;  
echo gettype($class);//string  
//原因和函数一样,PHP将Demo当成一个普通的裸字符串了  
Copy after login

As of PHP 5.2.3, there is another syntax for calling static methods of a class in PHP.

//PHP 5.2.3  
call_user_func('Demo::'.$action);
Copy after login

Starting from PHP 5.3, PHP introduced the concept of namespace, so the above call will become

call_user_func(__NAMESPACE__.'::Demo::'.$action);
Copy after login

Seeing the above code, you can actually guess that the static method of the class is just a function with a namespace prefix added.

Lambda and Closure in PHP

Before PHP 5.3, the syntax for implementing Lambda in PHP was very awkward. The code in the function had to be passed as a string to the create_function method for construction.

$lambda=create_function('$a','return addslashes(trim($a));');  
//相当于构造这样一个函数  
function lambda1($a) {  
    return addslashes(trim($a));  
}  
Copy after login

This kind of support for Lambda is really useless, and it actually reduces efficiency when used.

It is easy to make mistakes when writing code into strings. This style of lambda creation is only suitable for very short function expressions. Then take a look at what is stored in the $lambda variable above.

var_dump($lambda);  
//仍然是字符串类型,并且命名特点为"lambda_"加一个数字  
//后面的数字为PHP系统全局计数器,保证运行不会重复
Copy after login

In fact, what is created with create_function is still a global function, but the name of this global function will not be guessed.

Maybe we will try to create a function named like this:

function lambda_1() {  
    retunr 'Lambda!!!';  
}  
$lambda=create_function('','return 123;');  
//如果你的PHP是系统启动后第一次运行,那么$lambda里面的字符串看起来就和lambda_1一样  
//但执行代码调仍然一点没有错误  
echo $lambda();//返回123;  
echo lambda_1();//返回'Lambda!!!'  
Copy after login

Actually, the function name generated by create_function is somewhat special. It is the NULL character plus "lambda_" plus a numeric identifier. As for the NULL character, we cannot use this character when declaring the function, so the above code does not If there is a conflict, you can use the following code to test.

$lambda=create_function('','return 123;');  
preg_match('|\d+|',$lambda,$matches);//匹配出lambda数字标识  
//通lambda数字编号来调用些函数表达式  
call_user_func("\x00lambda_{$matches[0]}");//在字符串前面加个NULL字符  
//始终输出123  
Copy after login

Using create_function is not only awkward to write, but the create_function method can only create general temporary functions.

cannot implement closure (although if you just read some scalars, you can implement it differently, as follows)

function outer() {  
    $a=123;  
    return create_function('$a='.$a,'return $a;');  
}  
$inner=outer();  
echo $inner();  
//PHP有个很不爽的地主就是不把函数调用当成表达式,这种代码会出错  
//outer()();或getRow()[0];
Copy after login

As of PHP 5.3, PHP begins to support real closures, and lambda is easier to use and is close to JavaScript.

#!/usr/bin/php-5.3.0/php  
  
  
$data=range(0,10);  
//更接近于JavaScript的lambda语法  
$newData=array_map(function ($v) {  
    $a=range(0,$v);  
    return array_sum($a);  
},$data);  
  
function outer() {  
    $a=123;  
    //语法上生疏些,需要将要在lambda中访问的闭包变量列在use列表中  
    return function () use($a) {//闭包  
        echo $a;  
    };  
}  
$inner=outer();//只是不爽的地方就是,仍然不能这样写outer()();  
$inner();  
print_r($newData);  
  
//PHP也提供了像Lisp中的map,reduce,walk方法用于函数式编程  
//下面的代码用于将$_REQUEST中的每一个值进行trim  
array_walk('trim',$_REQUEST);  
Copy after login

There is a problem with variable references in PHP closures. The following code does not work as expected.

function outer() {  
    $a=0;  
    return function () use($a) {  
        return $a++;  
    };  
}  
$inner=outer();  
echo $inner();//outputs 0  
echo $inner();//outputs 0  
echo $inner();//outputs 0 
Copy after login

Because closures in PHP only copy the values ​​​​of the original variables, that is to say, the variables listed in use are local variables in the closure function at runtime, not outside the function. variable.

function outer() {  
    $a=0;  
    return function () use($a) {//大致相当于有这样一个步骤:lambda1::$a=outer::$a  
        return $a++;  
    };  
}  
Copy after login

If you want to achieve the imaginary state, just add a pass-by-reference flag before the variable.

function outer() {  
    $a=0;  
    return function () use(&$a) {  
        return $a++;  
    };  
}  
$inner=outer();  
echo $inner();//0  
echo $inner();//1  
echo $inner();//2  
echo $inner();//3
Copy after login

www.bkjia.comtruehttp: //www.bkjia.com/PHPjc/752432.htmlTechArticlePHP is not a functional programming language like Lisp. More importantly, PHP is suitable for writing code in C style . There is no such type of "function" in PHP, that is to say, functions cannot directly use variables...
Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template