목차
PHP中的Lambda及Closure
백엔드 개발 PHP 튜토리얼 在PHP里如何使用函数式编程_PHP教程

在PHP里如何使用函数式编程_PHP教程

Jul 13, 2016 am 10:33 AM
php 함수형 프로그래밍

PHP不是像Lisp那样的函数式编程语言,更多的,PHP适合用C的风格来编写代码。PHP中没有“函数”这种类型,也就是说,函数不能直接用变量来传递。比如下面的代码:

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

$test1 = test;
echo gettype($test1);
//输出string
로그인 후 복사

PHP是这样解析上面的代码的。

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

这表明PHP中的函数名在非调用的情况下(后面没有括号)会被当成一个字符串。

而正巧PHP中有通过一个字符串名称动态调用一个函数的方法:

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

//还有另外一种方式  
call_user_func('phpinfo');
로그인 후 복사

在C语言中可以通过指向函数的指针来将函数作为参数传递以实现高级的FP,而在PHP中,则是通过将函数名称作为字符串传递,通过$fname()来调用 ($fname是一个字符串类型的变量,其值为函数名),或者通过call_user_func来调用。那么到这里时就会发现PHP中函数的实现所带来的不便,因为函数是通过字符串来传递和调用的,那么就要求不能有函数名称相同的两个不同函数的存在。即,PHP中的所有的函数(这里所说的“函数”不包括方法)都是全局函数, 并且不允许在运行时重定义,因为如果允许重复定义函数(比如像大家熟悉的JavaScript那样),下面的代码就会出错:

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

既然PHP中所有函数都是全局函数,那么函数声明就自然不能嵌套着写了(指Closure),在讨论PHP中的Closure与Lambda之前先讨论一下PHP中的方法(即已经绑定到指定对象或类上的函数)。先创建一个简单的类,将其静态方法直接输出看看是什么内容。

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

那么如果要动态的调用一个类(或实例)的方法该怎么办呢? 先上一个现实中的例子,一个非常简单的Controller(当然真正的控制器不能这样简单)

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  
로그인 후 복사

除了使用PHP的可变变量机制外,还可以使用之前的call_user_func函数。

//传一个数组作为第一个参数,数组中第一个元素为类名,第二个元素为静态方法名称  
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专门用来调用对象的方法,但现在废弃不用了  
로그인 후 복사

如果需要调用实例的方法的话,则为

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));  
로그인 후 복사

从上面的代码可以看得出来,PHP中的类也是以字符串形式的名称传递的。像下面的代码:

$class=Demo;  
echo gettype($class);//string  
//原因和函数一样,PHP将Demo当成一个普通的裸字符串了  
로그인 후 복사

到了PHP 5.2.3时,PHP中调用类的静态方法还有另外一种语法。

//PHP 5.2.3  
call_user_func('Demo::'.$action);
로그인 후 복사

到了PHP 5.3开始,PHP引入了命名空间的概念,因此上面的调用将变成

call_user_func(__NAMESPACE__.'::Demo::'.$action);
로그인 후 복사

看到上面的代码,其实可以猜想,类的静态方法不就是加了一个命名空间前缀的函数嘛。

PHP中的Lambda及Closure

在PHP 5.3之前,PHP中实现Lambda的语法非常别扭,要将函数中的代码作为字符串传递给create_function方法去构造。

$lambda=create_function('$a','return addslashes(trim($a));');  
//相当于构造这样一个函数  
function lambda1($a) {  
    return addslashes(trim($a));  
}  
로그인 후 복사

这种对Lambda的支持真是鸡肋得很,用起来反而降低了效率。

将代码写到字符串中很容易出错,这种风格的lambda创建方式只适用于非常简短的函数表达式,那再看看上面的$lambda变量中保存的什么。

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

事实上用create_function创建的仍然是全局函数,只是这个全局函数的名字不会被猜到而已。

可能我们会尝试创建这样命名的函数:

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

其实,create_function生成的函数名有些特殊,它是NULL字符加上"lambda_"再加个一个数字标识,而NULL字符我们是没有办法在声明函数时使用这个字符的,因此上面的代码不会冲突,可以用下面的代码测试。

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

使用create_function不但写起来别扭,而且create_function方法只能创建一般的临时函数而已。

并不能实现闭包(虽然如果只是读取些标量的话可以变通一下实现,如下)

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

而到了PHP 5.3,PHP开始支持真正的闭包,而且lambda更好使了,接近于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);  
로그인 후 복사

PHP闭包中变量引用的问题,下面的代码工作起来和想像中有些差距。

function outer() {  
    $a=0;  
    return function () use($a) {  
        return $a++;  
    };  
}  
$inner=outer();  
echo $inner();//outputs 0  
echo $inner();//outputs 0  
echo $inner();//outputs 0 
로그인 후 복사

因为PHP中的闭包,只是对原变量中值进行拷贝而已,也就是说,use中列出来的变量,在运行时都是闭包函数中的局部变量,而并不是函数外面的变量。

function outer() {  
    $a=0;  
    return function () use($a) {//大致相当于有这样一个步骤:lambda1::$a=outer::$a  
        return $a++;  
    };  
}  
로그인 후 복사

如果要达到想像中的状态的话,只要在变量前加个按引用传值标识就行了。

function outer() {  
    $a=0;  
    return function () use(&$a) {  
        return $a++;  
    };  
}  
$inner=outer();  
echo $inner();//0  
echo $inner();//1  
echo $inner();//2  
echo $inner();//3
로그인 후 복사

www.bkjia.comtruehttp://www.bkjia.com/PHPjc/752432.htmlTechArticlePHP不是像Lisp那样的函数式编程语言,更多的,PHP适合用C的风格来编写代码。PHP中没有“函数”这种类型,也就是说,函数不能直接用变量...
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

Video Face Swap

Video Face Swap

완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

PHP에서 HTML/XML을 어떻게 구문 분석하고 처리합니까? PHP에서 HTML/XML을 어떻게 구문 분석하고 처리합니까? Feb 07, 2025 am 11:57 AM

이 튜토리얼은 PHP를 사용하여 XML 문서를 효율적으로 처리하는 방법을 보여줍니다. XML (Extensible Markup Language)은 인간의 가독성과 기계 구문 분석을 위해 설계된 다목적 텍스트 기반 마크 업 언어입니다. 일반적으로 데이터 저장 AN에 사용됩니다

JWT (JSON Web Tokens) 및 PHP API의 사용 사례를 설명하십시오. JWT (JSON Web Tokens) 및 PHP API의 사용 사례를 설명하십시오. Apr 05, 2025 am 12:04 AM

JWT는 주로 신분증 인증 및 정보 교환을 위해 당사자간에 정보를 안전하게 전송하는 데 사용되는 JSON을 기반으로 한 개방형 표준입니다. 1. JWT는 헤더, 페이로드 및 서명의 세 부분으로 구성됩니다. 2. JWT의 작업 원칙에는 세 가지 단계가 포함됩니다. JWT 생성, JWT 확인 및 Parsing Payload. 3. PHP에서 인증에 JWT를 사용하면 JWT를 생성하고 확인할 수 있으며 사용자 역할 및 권한 정보가 고급 사용에 포함될 수 있습니다. 4. 일반적인 오류에는 서명 검증 실패, 토큰 만료 및 대형 페이로드가 포함됩니다. 디버깅 기술에는 디버깅 도구 및 로깅 사용이 포함됩니다. 5. 성능 최적화 및 모범 사례에는 적절한 시그니처 알고리즘 사용, 타당성 기간 설정 합리적,

PHP에서 늦은 정적 결합을 설명하십시오 (정적 : :). PHP에서 늦은 정적 결합을 설명하십시오 (정적 : :). Apr 03, 2025 am 12:04 AM

정적 바인딩 (정적 : :)는 PHP에서 늦은 정적 바인딩 (LSB)을 구현하여 클래스를 정의하는 대신 정적 컨텍스트에서 호출 클래스를 참조 할 수 있습니다. 1) 구문 분석 프로세스는 런타임에 수행됩니다. 2) 상속 관계에서 통화 클래스를 찾아보십시오. 3) 성능 오버 헤드를 가져올 수 있습니다.

문자열로 모음을 계산하는 PHP 프로그램 문자열로 모음을 계산하는 PHP 프로그램 Feb 07, 2025 pm 12:12 PM

문자열은 문자, 숫자 및 기호를 포함하여 일련의 문자입니다. 이 튜토리얼은 다른 방법을 사용하여 PHP의 주어진 문자열의 모음 수를 계산하는 방법을 배웁니다. 영어의 모음은 A, E, I, O, U이며 대문자 또는 소문자 일 수 있습니다. 모음이란 무엇입니까? 모음은 특정 발음을 나타내는 알파벳 문자입니다. 대문자와 소문자를 포함하여 영어에는 5 개의 모음이 있습니다. a, e, i, o, u 예 1 입력 : String = "Tutorialspoint" 출력 : 6 설명하다 문자열의 "Tutorialspoint"의 모음은 u, o, i, a, o, i입니다. 총 6 개의 위안이 있습니다

php magic 방법 (__construct, __destruct, __call, __get, __set 등)이란 무엇이며 사용 사례를 제공합니까? php magic 방법 (__construct, __destruct, __call, __get, __set 등)이란 무엇이며 사용 사례를 제공합니까? Apr 03, 2025 am 12:03 AM

PHP의 마법 방법은 무엇입니까? PHP의 마법 방법은 다음과 같습니다. 1. \ _ \ _ Construct, 객체를 초기화하는 데 사용됩니다. 2. \ _ \ _ 파괴, 자원을 정리하는 데 사용됩니다. 3. \ _ \ _ 호출, 존재하지 않는 메소드 호출을 처리하십시오. 4. \ _ \ _ get, 동적 속성 액세스를 구현하십시오. 5. \ _ \ _ Set, 동적 속성 설정을 구현하십시오. 이러한 방법은 특정 상황에서 자동으로 호출되어 코드 유연성과 효율성을 향상시킵니다.

PHP 및 Python : 두 가지 인기있는 프로그래밍 언어를 비교합니다 PHP 및 Python : 두 가지 인기있는 프로그래밍 언어를 비교합니다 Apr 14, 2025 am 12:13 AM

PHP와 Python은 각각 고유 한 장점이 있으며 프로젝트 요구 사항에 따라 선택합니다. 1.PHP는 웹 개발, 특히 웹 사이트의 빠른 개발 및 유지 보수에 적합합니다. 2. Python은 간결한 구문을 가진 데이터 과학, 기계 학습 및 인공 지능에 적합하며 초보자에게 적합합니다.

PHP 실행 : 실제 예제 및 응용 프로그램 PHP 실행 : 실제 예제 및 응용 프로그램 Apr 14, 2025 am 12:19 AM

PHP는 전자 상거래, 컨텐츠 관리 시스템 및 API 개발에 널리 사용됩니다. 1) 전자 상거래 : 쇼핑 카트 기능 및 지불 처리에 사용됩니다. 2) 컨텐츠 관리 시스템 : 동적 컨텐츠 생성 및 사용자 관리에 사용됩니다. 3) API 개발 : 편안한 API 개발 및 API 보안에 사용됩니다. 성능 최적화 및 모범 사례를 통해 PHP 애플리케이션의 효율성과 유지 보수 성이 향상됩니다.

PHP : 웹 개발의 핵심 언어 PHP : 웹 개발의 핵심 언어 Apr 13, 2025 am 12:08 AM

PHP는 서버 측에서 널리 사용되는 스크립팅 언어이며 특히 웹 개발에 적합합니다. 1.PHP는 HTML을 포함하고 HTTP 요청 및 응답을 처리 할 수 ​​있으며 다양한 데이터베이스를 지원할 수 있습니다. 2.PHP는 강력한 커뮤니티 지원 및 오픈 소스 리소스를 통해 동적 웹 컨텐츠, 프로세스 양식 데이터, 액세스 데이터베이스 등을 생성하는 데 사용됩니다. 3. PHP는 해석 된 언어이며, 실행 프로세스에는 어휘 분석, 문법 분석, 편집 및 실행이 포함됩니다. 4. PHP는 사용자 등록 시스템과 같은 고급 응용 프로그램을 위해 MySQL과 결합 할 수 있습니다. 5. PHP를 디버깅 할 때 error_reporting () 및 var_dump ()와 같은 함수를 사용할 수 있습니다. 6. 캐싱 메커니즘을 사용하여 PHP 코드를 최적화하고 데이터베이스 쿼리를 최적화하며 내장 기능을 사용하십시오. 7

See all articles