Press "Enter" to skip to content

PHP8新特性之match表达式

PHP8 alpha2发布了,最近引入了一个新的关键字:match, 这个关键字的作用跟switch有点类似。

虽然我一般对语法糖无感,但这个我觉得还是有点意思,match这个词也挺好看,那么它是干啥的呢?

在以前我们可能会经常使用switch做值转换类的工作,类似:

switch ($input) {
    case "true":
        $result = 1;
    break;
    case "false":
        $result = 0;
    break;
    case "null":
        $result = NULL;
    break;
}

(当然,有的同学会说,谁会这么写,用个数组转换不行么? 拜托,这是举例啊,数组也只能数字键和整数啊,万一key是需要其他表达式呢,万一你要多个key对应一个值呢,对吧?)

那么如果使用match关键字呢,可以变成类似:

$result = match($input) {
        "true" => 1,
        "false" => 0,
        "null" => NULL,
};

相比switch, match会直接返回值,可以直接赋值给$result了。

并且,类似switch的多个case一个block一样,match的多个条件也可以写在一起,比如:

$result = match($input) {
    "true", "on" => 1,
    "false", "off" => 0,
    "null", "empty", "NaN" => NULL,
};

需要注意的和switch不太一样的是,以前我们用switch可能会经常遇到这种诡异的问题:

$input = "2 person";
switch ($input) {
    case 2:
        echo "bad";
    break;
}

你会发现,bad竟然被输出了,这是因为switch使用了宽松比较(==)。match就不会有这个问题了, 它使用的是严格比较(===),就是值和类型都要完全相等。

还有就是,当input并不能被match中的所有条件满足的时候,match会抛出一个UnhandledMatchError exception:

$input = "false";
$result = match($input) {
        "true" => 1,
};

会得到:

Fatal error: Uncaught UnhandledMatchError: Unhandled match value of type string

这样就不用担心万一match条件没写全导致了不可预知的错误。

另外还是要说明,match是关键字,也就是从PHP8开始它不能出现在namespace或者类名中,如果你的项目中有用match作为类名的:

class Match {}

在PHP8开始将会得到语法错误了, 当然,方法名中还是可以用的。

详细的,可以参考RFC:Match Expression

以上,没了。

77 Comments

  1. oktopus
    oktopus June 25, 2023

    What a great idea! I need this in my life.

  2. JaguarJack
    JaguarJack February 24, 2022

    基金会已经成立!可以支持一波。https://opencollective.com/phpfoundation

  3. Yang Xu
    Yang Xu December 1, 2021

    鸟哥,好久没有消息了,非常想念。
    本来一直是会看您微博动态的,但很久之前就不更新了。
    最近又去看了主页,发现好像之前微博也看不了了。
    不知道什么情况,希望鸟哥一切都好。
    还好看最近Github有活动,
    php8.1也发布了,不知道鸟哥怎么看fiber的加入

    • laruence
      laruence December 1, 2021

      都挺好,感谢挂念,只是在忙工作。
      至于怎么看Fiber,我感觉是个有益补充吧,一些异步的框架,应该会因此受益

  4. spizf
    spizf November 12, 2021

    浅显易懂

    • James.Long
      James.Long November 18, 2021

      测试下看看呢,听说现在博客都不能评论了

  5. 巡视官
    巡视官 September 6, 2021

    寂寞空庭春欲晚,梨花满地不开门。

  6. 毛英东
    毛英东 August 25, 2021

    原来switch这么危险,我得赶紧去检查一下代码

  7. 刘浪
    刘浪 July 31, 2021

    哥! 能不能给类加一个类似Java的static(){}啊。不然PHP的类方法真的太单调了。可操作的余地真的受限啊。

  8. Yang
    Yang June 20, 2021

    鸟哥微博也很久没更新了 不知道最近怎么样 特来问候下,祝鸟哥万事顺利

  9. steven
    steven June 17, 2021

    php8.0中是__construct()先执行,还是__get()先执行呢,我发现在__construct()加载了的全局方法,在__get()中居然用不了。

  10. steven
    steven June 17, 2021

    php8.0中是__construct(),先执行还是__get()先执行呢

  11. 容添下
    容添下 June 5, 2021

    麻雀虽小五脏俱全

  12. oforz
    oforz May 26, 2021

    鸟哥,对于目录魔法常量,在软链接路径时的限制,这有个问题,如果有空的话麻烦看看:
    zjz at zjz dot name 这个回复的内容
    https://bugs.php.net/bug.php?id=42516

  13. PHP 7.4.19,依然还没解决在 CentOS 7 上开启OPCACHE后,无法启动的问题~ Google 好久,其他人有这问题吗,PHP 7.3.X / 7.1 没有这个问题……

    $ /etc/init.d/php-fpm-7.4.19 configtest

    Tue May 11 17:32:38 2021 (25861): Fatal Error Unable to allocate shared memory segment of 134217728 bytes: unknown: Inappropriate ioctl for device (25)

    • hejxing
      hejxing July 3, 2021

      我也遇到过,被困惑了好长时间。最后发现是因为zlib库的问题,将原来的删除干净,重新安装zlib库就好了。

  14. 啦啦
    啦啦 April 23, 2021

    你好

  15. Tonight
    Tonight April 16, 2021

    能否写一些PHP网络编程的东西呀

  16. wilon
    wilon April 15, 2021

    匿名函数写法,看起来怪怪的😃

    $a = 1;
    echo match($a) {
    1 => (function () {
    return ‘dofunc’;
    })(),
    };

  17. 君马
    君马 April 13, 2021

    测试

  18. 君马
    君马 April 13, 2021

    太棒了

  19. Jane Dao
    Jane Dao March 11, 2021

    ??

  20. 野草
    野草 January 20, 2021

    不知是否有哪位大侠能帮忙继续维护php-beast,这项目挺好,可惜原作者好像不继续维护,不能支持最新PHP版本了
    或者哪位大侠能提供推荐个好的,支持最新PHP版本的加密扩展

  21. zhao liu chao
    zhao liu chao January 7, 2021

    php中的php-fpm会重写么?例如改成有几核的cpu开启几个php-fpm进程,php-fpm进程会开启协程或者线程处理请求。

  22. happy wheels
    happy wheels January 4, 2021

    Your article is very useful, the content is great, I have read a lot of articles, but for your article, it left me a deep impression, thank you for sharing.

    • hic
      hic December 31, 2020

      并发阻塞处理的解决方案,无论是一个良好的异步接口,或者一个完善轻量的类线程协程来处理阻塞,这也应该是PHP当前急需解决的,比单纯提高性能重要多了

      • shan
        shan December 31, 2020

        我觉得PHP学RUST就好.语言层面提供必要的async await的支持支持即可
        虽然目前通过yeild方式其实也勉强可以做,
        至于运行时[这东东见仁见智],还是觉得没必要写入到语言层面.
        至于一些IO的异步等 已经有不少的扩展了.
        框架选型,我觉得我会选 AMPHP, ReactPHP
        国内的SWOOLE这种.我个人不太喜欢.

  23. yangshengpu
    yangshengpu December 24, 2020

    我觉得PHP应该规范一下一些函数名称,这样看起来更严谨一些,一些函用下划线一些函数由多个单词组成,很长又不用下划线……。

  24. kn007
    kn007 December 9, 2020

    鸟哥,好久不见。
    请教个问题,我升级到php 8后,opcache还是老配置,但是phpinfo,没看到opcache工作。我配置增加jit相关配置,也不行,只留opcache.enable=1,也没工作。

    我尝试了opcache_*函数,都提示不存在,比如:
    Call to undefined function opcache_get_status()

    编译函数含 –enable-opcache。

    phpinfo唯一一个opcache相关是module author

    Opcache Andi Gutmans, Zeev Suraski, Stanislav Malyshev, Dmitry Stogov, Xinchen Hui

    • kn007
      kn007 December 9, 2020

      解决了,[Zend Modules]为空,才发现,加了引用so,可以了

  25. 王思彤
    王思彤 November 17, 2020

    很有用的一个功能

  26. Bourne
    Bourne November 16, 2020

    键值映射数组不好吗

    • Link
      Link November 29, 2020

      占内存

  27. 题海库
    题海库 October 27, 2020

    有相关资料推荐吗

  28. fage
    fage October 21, 2020

    swoole base模式不可以吗

  29. shooke
    shooke October 21, 2020

    rust中看过match,配合枚举使用还是挺方便的

  30. ybizi
    ybizi October 11, 2020

    惠先生您好,感谢你对PHP项目的贡献,让很多人受益非常多,也包括我。再次对您及所有PHP贡献者深表谢意

    我们现在使用PHP命令行加event做并发业务,PHP各方面表现都非常良好,但有个问题比较困扰我们,就是在某个消息处理中,一旦涉及访问到数据库,一旦数据库访问受阻,整个进程消息处理都会被阻塞等待PDO的接口返回,这严重影响了整个处理效能。

    我们研究过协程,研究过swoole,发现自己用php的yield解决这些没那么容易。swoole对此倒是有解决,但swoole无法在同一个进程中,又有server又同时可做client去连接外界,这会导致我们原来的处理需要修改非常多

    请问PHP官方是否可以内置开发一个类似swoole这样,可异步处理数据库的协程方式,这样相信PHP配合JIT,可以在更多领域得到应用,尤其是后台服务领域

    再次对您和PHP项目组的贡献表示感谢

    顺祝生活愉快,工作顺利

    • fage
      fage October 21, 2020

      swoole base模式不可以吗

      • ybizi
        ybizi October 29, 2020

        一、Base模式(SWOOLE_BASE)
        这种模式就是传统的异步非阻塞Server。在Reactor内直接回调PHP的函数。如果回调函数中有阻塞操作会导致Server退化为同步模式

        这个还是和我们现在问题一样。我们是希望能在不使用多进程情况下,有个类似协程这样的东西就能实现只阻塞某个处理或者能把数据库访问也完全异步的机制。

    • soen
      soen November 27, 2020

      我和你一样的问题,阻塞是个大麻烦

    • Bleakwind
      Bleakwind January 25, 2021

      Workerman 欢迎你, 可以试一试…

  31. jee
    jee September 29, 2020

    这个跟自己封装一个有啥区别

  32. jee
    jee September 29, 2020

    没啥作用

  33. chenpingbin
    chenpingbin September 17, 2020

    match 方法 虽然能抛出异常,但实际场景中很多的时候会有default 这个可能是match方法的一个短板。

    • wilon
      wilon April 15, 2021

      有的,看官方文档:https://www.php.net/manual/en/control-structures.match.php
      建议鸟哥上边的代码示例里加上default。

      default => ‘2333’,

  34. Ganlv
    Ganlv September 9, 2020

    php 的优势在于,发布容易、运维简单、语法简单、开发快速

    基于 HTTP 协议、请求回应式、REST API 这类东西都可以使用,而且天然的可以水平扩展。

    php 通常作为后端中的前端,由于业务侧可能经常变动,对外的接口可能会各种改变,php 的动态性非常棒,go 在这些方面是没法比的。

    真后端就是数据库、其他各种算法服务器了,这些服务是有状态的,php 不适合,这是 go 的主战场。

    • shan
      shan September 16, 2020

      转向RUST开发者表示GO就算了吧 哈哈
      match 在rust叫模式匹配.并不是简单的=== 配合enum牛逼的一逼.

  35. 啦啦啦
    啦啦啦 September 2, 2020

    啦啦啦啦啦我来啦

    • 啦啦啦
      啦啦啦 September 2, 2020

      啦啦啦啦啦我来啦啦啦啦啦啦我来啦

  36. oforz
    oforz August 21, 2020

    鸟哥,都PHP8了,还不考虑支持一下字符串的切片操作吗,就是python那样的 $abc[123:456]。现在使用函数调用substr,如果改为切片语法,应该对大量的临时分割效率有很大提高吧,像以前的unpack,现在是提供了第三个$offset参数,如果直接切片能通用得多了。

  37. owa10086
    owa10086 August 19, 2020

    js的switch是全等比较,和php有时候老是搞混

  38. Mark
    Mark August 15, 2020

    hi,冒昧打扰,
    其实有个困扰在我心中许久了,望能抽空解答下。

    PHP对于金额的计算,一般采取bc系列函數進行,
    而使用mysql存储时候,数据类型会通过decimal来存储。

    但是如果想在PHP中写个函数计算金额,之前得写法是:

    function addMoney($money,$numCnt=1){
    return bcmul($money,$numCnt,2);
    }

    如果希望指定数据类型,请问该怎么处理?
    如:
    function addMoney(float $money,int $numCnt):string
    {
    return bcmul($money,$numCnt,2);
    }

    这样感觉有点奇怪,MYSQL的decimal类型我不清楚是通过什么形式实现的,
    但是PHP有相对应的类型吗?float/double吗?如果数量过大会否有BUG?

    • Violet_ice紫冰
      Violet_ice紫冰 September 11, 2020

      是string类型

  39. Emrys.Liu
    Emrys.Liu July 23, 2020

    match 语法 alpha2 测试报解析错误, alpha3 才成功

  40. oforz
    oforz July 23, 2020

    鸟哥,PHP的array已经实现用[]赋值,有没有考虑过用{}来实现对象的定义?比较喜欢用对象的方式来做配置和参数,但是PHP的对象属性不能一次性初始化,很不方便。

    • Ganlv
      Ganlv September 9, 2020

      如果怕语法出错,像 JavaScript 解决箭头函数的函数体和直接返回值一样,加括号也行啊 ({a: 1})

  41. bao
    bao July 16, 2020

    说出理由

  42. a
    a July 14, 2020

    借鉴rust?

    • 白菜
      白菜 July 15, 2020

      这模式我第一看的时候是在erlang。不能说借鉴rust,rust也是集大成者。

  43. 雷柏利
    雷柏利 July 14, 2020

    您好!鸟哥。我是一名在国内4线城市的普通php开发者。php社区可不可以成立php基金会?借助php基金会推广、保护并提升php编程语言,促进php社区持续发展。php在我们国内使用还是相对比较多,以我们国家的国力水平维护一个全球性的编程语言基金会应该不会太差。

    • hello
      hello July 14, 2020

      转go吧

      • 恩佐Enzo
        恩佐Enzo August 20, 2020

        从楼主表达中 可见对php 热爱之情!你这句话 有点扎心啊 兄嘚!

      • shan
        shan September 16, 2020

        RUST表示学GO不如洗洗睡吧.
        不搞语言混战
        GO的优势比PHP块 但对RUST来说呵呵
        PHP比GO慢 但你一个PHPER转GO意义在哪?

    • Ben Huang
      Ben Huang July 17, 2020

      组织整合社区感觉可行,成立基金会大公司牵头更好些,社区牵头没核心经济来源额

Comments are closed.