jjzjj

php - 在这些条件下发生了什么?

coder 2024-04-15 原文

使用开关:

switch($page){
    case 'dog':
    case 'cat':
    case 'robot':
    case 'default':{

        break;
    };
    default:{

        break;
    }
}

如果:

if($page == 'dog' || $page == 'cat' || $page == 'robot' || $page == 'default'){

}else{

}

使用针和干草堆:

$pages = array('dog', 'cat', 'robot', 'default');
if(in_array($page, $pages)){

}else{

}

I would like to know what is happening under-the-hood.


平均速度:

  • needle 执行时间:0.054877042770386 秒
  • if 执行时间:0.014014959335327 秒
  • switch 执行时间:0.0093550682067871 秒

最佳答案

所有使用 VLD 输出的场景(PHP 5.6.4)

切换

number of ops:  31
compiled vars:  !0 = $page
line     #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   2     0  E >   EXT_STMT                                                 
         1        ASSIGN                                                   !0, 'default'
   3     2        NOP                                                      
   4     3        EXT_STMT                                                 
         4        CASE                                             ~1      !0, 'dog'
         5      > JMPZ                                                     ~1, ->7
   5     6    > > JMP                                                      ->10
         7    >   EXT_STMT                                                 
         8        CASE                                             ~1      !0, 'cat'
         9      > JMPZ                                                     ~1, ->11
   6    10    > > JMP                                                      ->14
        11    >   EXT_STMT                                                 
        12        CASE                                             ~1      !0, 'robot'
        13      > JMPZ                                                     ~1, ->15
   7    14    > > JMP                                                      ->18
        15    >   EXT_STMT                                                 
        16        CASE                                             ~1      !0, 'default'
        17      > JMPZ                                                     ~1, ->23
        18    >   NOP                                                      
   9    19        EXT_STMT                                                 
        20      > BRK                                                      1, ->30
  11    21*       EXT_STMT                                                 
        22*       JMP                                                      ->25
        23    >   EXT_STMT                                                 
        24      > JMP                                                      ->29
        25    >   NOP                                                      
  13    26        EXT_STMT                                                 
        27      > BRK                                                      1, ->30
  15    28*       JMP                                                      ->30
        29    > > JMP                                                      ->25
  16    30    > > RETURN                                                   1

如果

number of ops:  16
compiled vars:  !0 = $page
line     #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   2     0  E >   EXT_STMT                                                 
         1        ASSIGN                                                   !0, 'default'
   3     2        EXT_STMT                                                 
         3        IS_EQUAL                                         ~1      !0, 'dog'
         4      > JMPNZ_EX                                         ~1      ~1, ->7
         5    >   IS_EQUAL                                         ~2      !0, 'cat'
         6        BOOL                                             ~1      ~2
         7    > > JMPNZ_EX                                         ~1      ~1, ->10
         8    >   IS_EQUAL                                         ~3      !0, 'robot'
         9        BOOL                                             ~1      ~3
        10    > > JMPNZ_EX                                         ~1      ~1, ->13
        11    >   IS_EQUAL                                         ~4      !0, 'default'
        12        BOOL                                             ~1      ~4
        13    > > JMPZ                                                     ~1, ->15
   5    14    > > JMP                                                      ->15

针和干草堆

number of ops:  17
compiled vars:  !0 = $page, !1 = $pages
line     #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   2     0  E >   EXT_STMT                                                 
         1        ASSIGN                                                   !0, 'default'
   3     2        EXT_STMT                                                 
         3        INIT_ARRAY                                       ~1      'dog'
         4        ADD_ARRAY_ELEMENT                                ~1      'cat'
         5        ADD_ARRAY_ELEMENT                                ~1      'robot'
         6        ADD_ARRAY_ELEMENT                                ~1      'default'
         7        ASSIGN                                                   !1, ~1
   4     8        EXT_STMT                                                 
         9        EXT_FCALL_BEGIN                                          
        10        SEND_VAR                                                 !0
        11        SEND_VAR                                                 !1
        12        DO_FCALL                                      2  $3      'in_array'
        13        EXT_FCALL_END                                            
        14      > JMPZ                                                     $3, ->16
   6    15    > > JMP                                                      ->16
   9    16    > > RETURN                                                   1

如您所见,开关实际上具有最多的操作,但在您的测试用例中是最快的(有兴趣看到它,因为我想这些方法中的每一个在特定情况下都可能是“最佳”)

虽然操作不是标准的工作量,但它们确实给出了指示。

一点比较

Switch 使用了很多CASE(检查两个值是否相等)和JMPZ(如果地址为零则跳转)。

If 语句使用 IS_EQUAL,这与 case 类似,但第二个值必须是常量。我认为这会减慢检查速度,因为现在有 2 个变量可以检查。 (您的基准测试结果似乎与此一致)

接下来使用函数调用。函数在 PHP 中通常被认为很慢 https://github.com/php/php-src/blob/df29df7ec40cf7950a98f36bfa99ef19f0950309/ext/standard/array.c#L1595

是函数的 C 源代码,每种类型的变量都有不同的逻辑。假设我们使用的是字符串,数组被循环并用

检查每个值

https://github.com/php/php-src/blob/213b49620d24ebebe3cf19787ee6e3448d27d046/Zend/zend_operators.h#L712

尽可能早点回来。

基准脚本

$max_checks = 1000000;

$bench = -microtime(true);
for($i = 0;$i < $max_checks; $i++) {
  switch($page){
    case 'dog':
    case 'cat':
    case 'robot':
    case 'default':{
       break;
     };
    default:{

      break;
    }
  }
}
echo "\nSwitch took " . (microtime(true) + $bench);

$bench = -microtime(true);


for($i = 0;$i < $max_checks; $i++) {
  $page == 'dog' || $page == 'cat' || $page == 'robot' || $page == 'default';
}
echo "\nif took " . (microtime(true) + $bench);


$pages = array('dog', 'cat', 'robot', 'default');

$bench = -microtime(true);
for($i = 0;$i < $max_checks; $i++) {
  (in_array($page, $pages));
}

echo "\nneedle haystack took " . (microtime(true) + $bench);

传入 $page = 'dog';

Switch took 0.31698203086853
if took 0.18721604347229
needle haystack took 1.5701420307159

传入 $page = 'default';

Switch took 0.46866297721863
if took 0.40072298049927
needle haystack took 1.6747360229492

传入$page = 'no match';

Switch took 0.52629804611206
if took 0.40276217460632
needle haystack took 1.6838929653168

我不确定你使用的是什么输入,但 if 和 switch 对我来说很相似(switch 的边缘更具可读性)

编辑:

1 个更快的测试用例。 使用 if 和 ===

这会将 IS_EQUAL 调用替换为 IS_IDENTICAL

有轻微的加速

所有测试用例

if      took 0.43217587471008
if(===) took 0.39284706115723

操作码列表 http://php.net/manual/en/internals2.opcodes.list.php

编辑数字 2

因为无论如何我都在测试 PHP 7 RC3。

基准测试重新运行(在同一台机器上)

$page = '狗';

Switch took 0.018393993377686
if took 0.030646085739136
if(===) took 0.036449909210205
needle haystack took 0.045974969863892

$page = 'default';

Switch took 0.040921211242676
if took 0.085216999053955
if(===) took 0.1043848991394
needle haystack took 0.052649974822998

$page = '不匹配';

Switch took 0.059795141220093
if took 0.080615997314453
if(===) took 0.10486197471619
needle haystack took 0.049200057983398

在 PHP 7 中,针和大海捞针看起来最好

关于php - 在这些条件下发生了什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32637827/

有关php - 在这些条件下发生了什么?的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  3. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  4. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  5. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

    为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

  6. ruby - ruby 中的 TOPLEVEL_BINDING 是什么? - 2

    它不等于主线程的binding,这个toplevel作用域是什么?此作用域与主线程中的binding有何不同?>ruby-e'putsTOPLEVEL_BINDING===binding'false 最佳答案 事实是,TOPLEVEL_BINDING始终引用Binding的预定义全局实例,而Kernel#binding创建的新实例>Binding每次封装当前执行上下文。在顶层,它们都包含相同的绑定(bind),但它们不是同一个对象,您无法使用==或===测试它们的绑定(bind)相等性。putsTOPLEVEL_BINDINGput

  7. ruby - Infinity 和 NaN 的类型是什么? - 2

    我可以得到Infinity和NaNn=9.0/0#=>Infinityn.class#=>Floatm=0/0.0#=>NaNm.class#=>Float但是当我想直接访问Infinity或NaN时:Infinity#=>uninitializedconstantInfinity(NameError)NaN#=>uninitializedconstantNaN(NameError)什么是Infinity和NaN?它们是对象、关键字还是其他东西? 最佳答案 您看到打印为Infinity和NaN的只是Float类的两个特殊实例的字符串

  8. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

  9. ruby - 为什么 SecureRandom.uuid 创建一个唯一的字符串? - 2

    关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion为什么SecureRandom.uuid创建一个唯一的字符串?SecureRandom.uuid#=>"35cb4e30-54e1-49f9-b5ce-4134799eb2c0"SecureRandom.uuid方法创建的字符串从不重复?

  10. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

    我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

随机推荐