2015-10-05 11 views
29

PHP7以降、今はuse scalar typehint and ask for strict types on a per-file basisになります。これらの機能を使用することによるパフォーマンス上の利点はありますか?はいの場合、どうですか?PHP7のスカラー型と厳密型はパフォーマンス向上機能ですか?

    の他のコードを使用するときに誤解を避け、不要な型変換の問題
  • にもっとセマンティックなコードを避ける
  • より正確なエラー
  • 、私のような概念の利点を、唯一見つけたinterwebsアラウンド

  • コードのより良いIDE評価
+3

スカラー型ヒントの潜在的にパフォーマンスを向上させる効果の1つは、型キャストが早期に発生するように強制されるため、後続のキャスト数を減らす可能性があります。 – NikiC

答えて

32

今日、スカラーとストライドの使用PHP7のct型はパフォーマンスを向上させません。

PHP7にはJITコンパイラがありません。

将来、PHPがJITコンパイラを取得する場合、追加の型情報で実行できる最適化を想像するのは難しくありません。

JITを使用しない最適化については、スカラー型はほんの一部に役立ちます。

のは、次のコードを見てみましょう:

<?php 
function (int $a, int $b) : int { 
    return $a + $b; 
} 
?> 

これはそのためのZendによって生成されたコードです:

function name: {closure} 
L2-4 {closure}() /usr/src/scalar.php - 0x7fd6b30ef100 + 7 ops 
L2 #0  RECV     1           $a     
L2 #1  RECV     2           $b     
L3 #2  ADD      $a     $b     ~0     
L3 #3  VERIFY_RETURN_TYPE  ~0                
L3 #4  RETURN     ~0                
L4 #5  VERIFY_RETURN_TYPE                  
L4 #6  RETURN     null 

ZEND_RECVは、受信したパラメータの検証および強制を入力し実行オペコードです。次のオペコードはZEND_ADDです:

ZEND_VM_HANDLER(1, ZEND_ADD, CONST|TMPVAR|CV, CONST|TMPVAR|CV) 
{ 
    USE_OPLINE 
    zend_free_op free_op1, free_op2; 
    zval *op1, *op2, *result; 

    op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); 
    op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); 
    if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_LONG)) { 
     if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) { 
      result = EX_VAR(opline->result.var); 
      fast_long_add_function(result, op1, op2); 
      ZEND_VM_NEXT_OPCODE(); 
     } else if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_DOUBLE)) { 
      result = EX_VAR(opline->result.var); 
      ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) + Z_DVAL_P(op2)); 
      ZEND_VM_NEXT_OPCODE(); 
     } 
    } else if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_DOUBLE)) { 
     if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_DOUBLE)) { 
      result = EX_VAR(opline->result.var); 
      ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2)); 
      ZEND_VM_NEXT_OPCODE(); 
     } else if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) { 
      result = EX_VAR(opline->result.var); 
      ZVAL_DOUBLE(result, Z_DVAL_P(op1) + ((double)Z_LVAL_P(op2))); 
      ZEND_VM_NEXT_OPCODE(); 
     } 
    } 

    SAVE_OPLINE(); 
    if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op1) == IS_UNDEF)) { 
     op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); 
    } 
    if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op2) == IS_UNDEF)) { 
     op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); 
    } 
    add_function(EX_VAR(opline->result.var), op1, op2); 
    FREE_OP1(); 
    FREE_OP2(); 
    ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); 
} 

そのコードのいずれかが、あなたはそれがかなり複雑だということを見ることができないものを理解せず。

そこでターゲットを完全ZEND_RECVを省略し、paramsはの種類が知られているので、または分岐(ガードを越えて)任意のチェックを実行する必要はないZEND_ADD_INT_INTZEND_ADDを交換することになります。

これらを省略してZEND_ADD_INT_INTを指定するには、コンパイル時に$a$bのタイプを確実に推測できる必要があります。例えば、$a$bのようなコンパイル時の推論は、リテラルの整数または定数です。

文字どおりyesterday、PHP 7.1には本当に似たようなものがあります:ZEND_ADDのようないくつかの高周波オペコード用の型指定ハンドラがあります。 Opcacheは、それはいくつかのケースでは、アレイ内の変数の型を推論し、種類の特定のハンドラを使用するように、通常のZEND_ADDを使用するために生成されたオペコードを変更することさえできます、いくつかの変数の型を推論することができます:

ZEND_VM_TYPE_SPEC_HANDLER(ZEND_ADD, (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG), ZEND_ADD_LONG_NO_OVERFLOW, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(NO_CONST_CONST,COMMUTATIVE)) 
{ 
    USE_OPLINE 
    zval *op1, *op2, *result; 

    op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); 
    op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); 
    result = EX_VAR(opline->result.var); 
    ZVAL_LONG(result, Z_LVAL_P(op1) + Z_LVAL_P(op2)); 
    ZEND_VM_NEXT_OPCODE(); 
} 

繰り返しますが、何が起こっているのか理解していなければ、これはであり、実行するのがさらに簡単です。です。

これらの最適化は非常にクールですが、最も効果的で最も興味深い最適化は、PHPにJITがある場合に発生します。

+4

正確に言えば、それはパフォーマンスを非常に小さくすることさえあります。無視できる量;-)これはいくつかのチェックを少なくしていますが、実際には目立たないものです。 – bwoebi

+2

これは技術的に真です。しかし、そのような機能を使用する(またはしない)かどうかは、機能強化や劣化が決定的要因ではありません。 –

14

これらの機能を使用すると、パフォーマンス上の利点はありますか?はいの場合、どうですか?

なしまだです。

しかしこれは、より効率的なopcode生成のための第一歩です。スカラー型のヒントのFuture ScopeRFCによると、スカラ型ヒントは渡された引数が(少なくとも最初は)関数本体内 特定のタイプであることを保証するので

、これは で使用することができ最適化のためのZend Engineたとえば、 関数がfloat-hinted引数を2つとり、 で算術演算を行う場合、算術演算子はオペランドの型 をチェックする必要はありません。 PHPの以前のバージョンで

FacebookのHHVMが行うように、優れた性能を達成するためにJITコンパイルのアプローチを持っていることは本当に難しい可能関数に渡すことができ、パラメータの種類を知る方法はありませんでした。

@ircmaxellの彼のblogには、ネイティブコンパイルでこれをすべて次のレベルに引き上げる可能性が言及されています。これはJITより優れています。

パフォーマンスの観点から、スカラーヒントは、これらの最適化を実装するためのヒントを開きます。しかし、それ自体のパフォーマンスを向上させるものではありません。

関連する問題