ホームページ >バックエンド開発 >PHPチュートリアル >PHP の型変換に関するインタビューの質問
原文はブログに掲載しています http://starlight36.com/post/php-type-convert
最近、会社の新人面接をしているのですが、よく聞かれる質問が価値観です。例:
var_dump((int)true);var_dump((string)true);var_dump((string)false);var_dump((bool)"1");var_dump((bool)"0");var_dump((bool)"");var_dump((bool)"false");
私がこの質問を初めて目にしたのは、Yingji の PHP シニア開発エンジニアの職の筆記試験でした。これは非常に基本的なことですが、それでも多くの PHP 使用者を困惑させる可能性があります。まず実行結果を見てみましょう:
int(1)string(1) "1"string(0) ""bool(true)bool(false)bool(false)bool(true)
ほとんどの人にとって、1、2、4 行目は通常問題ありません。しかし、なぜ false が空の文字列に変換されるのでしょうか?リクエスト値を処理するとき、通常は文字列型 false が渡されますが、「false」(文字列)は false(ブール値)ではないため、少し混乱します。
なぜこれが起こっているのですか?
この問題に関して、PHP カーネルから始めて、型変換中にシステム内で何が起こるかを見てみましょう。
まず、PHP の弱い型の実装に関する背景知識を追加しましょう。もちろん、PHP インタプリタは C 言語で記述され、変数の最終処理も C 言語を使用して実装され、データ構造が構築されます。 Zend エンジンでは、対応する PHP 変数の型は zval です。
Zend/zend_types.h ファイルを開くと、zval 型の定義が表示されます。php-5.5.23 バージョンは 55 行目あたりにあります:
typedef struct _zval_struct zval;
このようにして、zval が実際には _zval_struct Type という名前の構造体であることがわかります。 Zend/zend.h ファイルの 320 行目あたりから始まるこの構造体の定義を見つけました。
typedef union _zvalue_value { long lval; /* long value */ double dval; /* double value */ struct { char *val; int len; } str; HashTable *ht; /* hash table value */ zend_object_value obj;} zvalue_value;struct _zval_struct { /* Variable information */ zvalue_value value; /* value */ zend_uint refcount__gc; zend_uchar type; /* active type */ zend_uchar is_ref__gc;};
ご覧のとおり、_zval_struct には 2 つの重要なメンバーが含まれています。1 つは zvalue_value 型の値で、もう 1 つはzend_uchar 型の型。 zvalue_value 型は共用体であり、PHP 変数の値に関する情報を格納するために使用されることに注意してください。 (ユニオンが何であるかを忘れた場合は、説明しましょう。ユニオンは構造体に似ていますが、ユニオンにはメンバーが 1 つしか存在できず、ユニオンが占有するスペースはユニオン内で最も長くなります。メンバーが長いほど、ユニオンにはメンバーが 1 つしか存在できません。これはメモリ使用量を節約するために行われます。) zvalue_value には、long、double、struct、HashTable、zend_object_value の 5 種類のメンバーがあります。これらは、PHP 変数のさまざまなタイプの値を保存するために使用されます:
C タイプ | PHP タイプ |
long | bool |
int | |
リソース | |
ダブル | float |
struct | string |
HashTable | 配列 |
オブジェクト |
PHP の変数の型変換、つまり弱い型の実装は、基本的に異なる型間の zval 型の変換を実装していることがわかります。 zvalue_value の数値変換を完了することに加えて、_zval_struct の型を現在の変数の型に設定する必要もあります。この変換を完了するために、一連の関数 Convert_to_* が Zend エンジンに実装されています。これらの変換関数は、Zend/zend_operators.c の 511 行目あたりにあります。
ZEND_API void convert_to_boolean(zval *op) /* {{{ */{ int tmp; switch (Z_TYPE_P(op)) { case IS_BOOL: break; case IS_NULL: Z_LVAL_P(op) = 0; break; case IS_RESOURCE: { TSRMLS_FETCH(); zend_list_delete(Z_LVAL_P(op)); } /* break missing intentionally */ case IS_LONG: Z_LVAL_P(op) = (Z_LVAL_P(op) ? 1 : 0); break; case IS_DOUBLE: Z_LVAL_P(op) = (Z_DVAL_P(op) ? 1 : 0); break; case IS_STRING: { char *strval = Z_STRVAL_P(op); if (Z_STRLEN_P(op) == 0 || (Z_STRLEN_P(op)==1 && Z_STRVAL_P(op)[0]=='0')) { Z_LVAL_P(op) = 0; } else { Z_LVAL_P(op) = 1; } STR_FREE(strval); } break; case IS_ARRAY: tmp = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0); zval_dtor(op); Z_LVAL_P(op) = tmp; break; case IS_OBJECT: { zend_bool retval = 1; TSRMLS_FETCH(); convert_object_to_type(op, IS_BOOL, convert_to_boolean); if (Z_TYPE_P(op) == IS_BOOL) { return; } zval_dtor(op); ZVAL_BOOL(op, retval); break; } default: zval_dtor(op); Z_LVAL_P(op) = 0; break; } Z_TYPE_P(op) = IS_BOOL;}/* }}} */
case。 IS_STRING このコードは文字列型変数をブール型に変換する演算です。文字列が空であるか、文字列の長さが 1 で文字が 0 の場合にのみ、文字列のブール値が 1 (true)、その他の値が 0 (false) であることがわかります。 。
同様に、ブール値がどのように文字列に変換されるかについても理解しています。これは、_convert_to_string 関数の実装から理解できます。
一見単純かつ基本的な PHP の問題の根本原因は、PHP 実装メカニズムの把握にあります。個人的には、この質問は PHPer の知識の境界を特定するのにも適した質問であると感じています。