Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Speaker Deck
PRO
Sign in
Sign up for free
PHPの緩やかな比較の実態
ゆい
April 11, 2022
Programming
0
250
PHPの緩やかな比較の実態
ゆい
April 11, 2022
Tweet
Share
Other Decks in Programming
See All in Programming
CIでAndroidUIテストの様子を録画してみた
mkeeda
0
190
Explore Java 17 and beyond
josepaumard
3
670
Update from the Elixir team - 2022
whatyouhide
0
200
Unity Localization で多言語対応実装しよう / xrdnk-yokohamaunity-lt10-20220513
xrdnk
0
180
脱オブジェクト指向講座(5分LT資料)
kishida
8
11k
マイクロインタラクション入門〜ディテイルにこだわるエンジニアリング〜
swimmyxox
0
120
You CANt teach an old dog new tricks
michaelbukachi
0
120
「新卒だけ」じゃない!学び直しを支えるミクシィの技術研修を紹介
mixi_engineers
PRO
0
240
スモールチームがAmazon Cognitoでコスパよく作るサービス間連携認証
tacke_jp
2
920
Nix for Scala folks
kubukoz
0
140
roadmap to rust 2024
matsu7874
1
910
機能横断型チームにおける技術改善
takeshiakutsu
3
510
Featured
See All Featured
Scaling GitHub
holman
451
140k
Typedesign – Prime Four
hannesfritz
33
1.3k
Fontdeck: Realign not Redesign
paulrobertlloyd
73
4.1k
Web Components: a chance to create the future
zenorocha
303
40k
Become a Pro
speakerdeck
PRO
3
790
Adopting Sorbet at Scale
ufuk
63
7.5k
Code Reviewing Like a Champion
maltzj
506
37k
Keith and Marios Guide to Fast Websites
keithpitt
404
21k
How to Ace a Technical Interview
jacobian
265
21k
Testing 201, or: Great Expectations
jmmastey
21
5.4k
Why Our Code Smells
bkeepers
PRO
324
54k
Java REST API Framework Comparison - PWX 2021
mraible
PRO
11
4.6k
Transcript
Copyright© M&AΫϥυ PHPͷ؇͔ͳൺֱͷ࣮ଶ PHPerKaigi 2022
Copyright© M&AΫϥυ 2 Profile גࣜձࣾM&AΫϥυ ᅳଜʢΏ͍ʣ fyui001 @fyui_001
Copyright© M&AΫϥυ 3 ֓ཁ PHPʹՁԋࢉࢠ͕2ͭ͋Γ·͢ɻʮ==ʯͱʮ===ʯͰ͢ɻ લऀ؇͔ͳൺֱɺޙऀݫີͳൺֱ͕ߦΘΕ·͢ɻ PHPerͷํͳΒΑ͘͝ଘͩͱࢥ͍·͢ɻ ࠓճલऀͷ؇͔ͳൺֱΛ࣮ଶ͕Ͳ͏ͳ͍ͬͯΔͷ͔Λͬͯݟ͍ͨͱࢥ͍·͢ɻ
Copyright© M&AΫϥυ 4 ؇͔ͳൺֱͷΧΦε͞ ྫ: <?php var_dump(0 == '00'); var_dump('00'
== '0000'); var_dump('01' == '001'); ग़ྗ: bool(true) bool(true) bool(true)
Copyright© M&AΫϥυ 5 ؇͔ͳൺֱͷΧΦε͞ ͍ɺҙຯΘ͔Γ·ͤΜɻ 1, 2ߦཧղͰ͖ͳ͍͜ͱ͋Γ·ͤΜ͕ 3ߦ͕ԿނtrueʹͳΔͷ͔ɺݫີʹઆ໌͢ΔʹͲ͏ͨ͠Β͍͍Ͱ͠ΐ ͏͔ɻ ͜ͷൃදΛฉ͍ͯཧղ͠આ໌Ͱ͖ΔΑ͏ʹͳͬͯ͑Εخ͍͠Ͱ͢ɻ
Copyright© M&AΫϥυ 6 ؇͔ͳൺֱͷ࣮ମͲ͜ʹ͋Δͷ͔ ݴޠ༷ʹؔ͢Δઆ໌υΩϡϝϯτΛಡΊྑ͍ͷͰ͕͢ɺ ࠷ਖ਼֬ͳυΩϡϝϯτԿͰ͠ΐ͏ɻ ͦΕιʔείʔυͰ͢ɻ ιʔείʔυͱͦΕΛઆ໌͍ͯ͠ΔυΩϡϝϯτʹࠩҟ͕͋ͬͯɺͦ ͷιʔείʔυͰಈ͍͍ͯΔҎ্ιʔείʔυ͕ਖ਼֬ͳυΩϡϝϯτ ʹͳΓ·͢ɻ
PHPͷ؇͔ͳൺֱΛߦ͍ͬͯΔιʔείʔυຊମΛݟͯΈ·͠ΐ͏ɻ
Copyright© M&AΫϥυ 7 ؇͔ͳൺֱͷ࣮ମͲ͜ʹ͋Δͷ͔ ࠓճPHP8.0.9ͷιʔείʔυΛಡΜͰ͍͜͏ͱࢥ͍·͢ɻ
Copyright© M&AΫϥυ 8 ιʔείʔυͷམͱ͠ํ ·ͣී௨ʹgit clone͠·͢ git clone https://github.com/php/php-src
Copyright© M&AΫϥυ 9 ιʔείʔυͷམͱ͠ํ ࠓͷphp-srcͷ࠷৽PHP8.1.4ͷRCʹͳ͍ͬͯΔͷͰɺ8.0.9ʹΞοϓ σʔτ͞ΕͨίϛοτΛಛఆͯ͠νΣοΫΞτͯ͋͛͠·͢ɻ git checkout a5368c55be0a42af9fdc2c76fb0c2a06a42ddf36
Copyright© M&AΫϥυ 10 PHPͷ؇͔ͳൺֱͷ࣮ଶ ʊਓਓਓਓਓਓਓਓਓਓਓਓਓਓਓਓਓਓਓਓਓਓਓਓਓਓਓਓਓਓਓਓਓਓਓʊ ʼɹPHPͷ؇͔ͳൺֱಈ࡞Λݫີʹઆ໌Ͱ͖Δਓ͔͍͚ͬͯ͠·ͤΜɻɹʻ ʉY^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^ ʉ
Copyright© M&AΫϥυ 11 ֘ιʔεʹḷΓண͘ํ๏ ϊʔώϯτͰPHPͷιʔείʔυΛಡΜͰɺతͷॴʹͨͲΓண ͚ͳ͚Εҙຯ͕͋Γ·ͤΜɻ ݴޠಛ༗ͷԋࢉࢠΛจࣈྻͰgrepIDEͷϑΝΠϧݕࡧΛͯ͠Έ·͢ɻ ࠓճӉધԋࢉࢠ(<=>)Ͱݕࡧͯ͠Έ·͢ɻ
Copyright© M&AΫϥυ 12 ֘ιʔεʹḷΓண͘ํ๏ ͳΜ͔ͦΕͬΆ͍ϑΝΠϧ͕ݟ͔ͭΓ·ͨ͠ɻ PHPͷԋࢉࢠΛจࣈྻͱͯ͠ఆ͍ٛͯ͠ΔࠜຊZend/ zend_language_parser.yʹ͋Γͦ͏Ͱ͢ɻ ※.yͷ֦ுࢠͷϑΝΠϧߏจղੳػΛੜ͢ΔͨΊʹɺYaccͱݴ͏πʔ ϧͷϑΝΠϧͷԋࢉࢠͰ͢ɻ Zend/zend_language_parser.yΛ։͍ͯΈ·͢ɻ
Copyright© M&AΫϥυ 13 ֘ιʔεʹḷΓண͘ํ๏ Ӊધԋࢉࢠͷ্͙͢ʹո͍͠ߦ͕͋Γ·ͨ͠ɻ తͷʮ==ʯT_IS_EQUALͱ͍͏໊લ͕͍͍ͯΔΈ͍ͨͰ͢ɻ Zend/zend_language_parser.yͰT_IS_EQUALΛݕࡧ͢Δͱ
Copyright© M&AΫϥυ 14 ֘ιʔεʹḷΓண͘ํ๏ ͜Μͳιʔε͕ݟ͔ͭΓ·͢ɻ Ͳ͏ΒZEND_IS_EQUALͱ͍͏໊લͰதؒίʔυʹม͞ΕΔΈͨ ͍Ͱ͢ɻ
Copyright© M&AΫϥυ 15 ZEND_IS_EQUALͱݴ͏ϫʔυΛෳϑΝΠϧݕࡧ͢Δͱɺ Zend/zend_opcode.cʹ͜Μͳߦ͕͋Γ·ͨ͠ case ZEND_IS_EQUAL:
Copyright© M&AΫϥυ 16 Zend/zend_opcode.cͷத END_API binary_op_type get_binary_op(int opcode) { switch
(opcode) { /* ~~~~~~~~~~ */ case ZEND_IS_EQUAL: case ZEND_CASE: return (binary_op_type) is_equal_function; case ZEND_IS_NOT_EQUAL: return (binary_op_type) is_not_equal_function; /* ~~~~~~~~~~ */ default: ZEND_UNREACHABLE(); return (binary_op_type) NULL; } } ͜Μͳͷ͕͍·ͨ͠ɻ ZEND_IS_EQUALis_equal_functionͱ͍͏ؔʹରԠ͍ͯ͠ΔΑ͏Ͱ͢Ͷɻ is_equal_functionͰݕࡧΛ͔͚ͯΈ·͢ɻ
Copyright© M&AΫϥυ 17 is_equal_functionͰݕࡧΛ͔͚ͯΈΔ ZEND_API int ZEND_FASTCALL is_equal_function(zval *result, zval
*op1, zval *op2) Zend/zend_operators.cʹḷΓண͖·ͨ͠ɻ ϊʔώϯτͰɺIDEͷϑΝΠϧݕࡧͰେͨ࣌ؒ͠Λ͔͚ͣʹ΄͍͠ ใ·ͰḷΓண͚·͢ɻ ϥΠϒϥϦͷதΛௐ͍ͨͱ͖ʹ͑ΔͷͰࢀߟʹͯ͠Έͯ͘ ͍ͩ͞ɻ
Copyright© M&AΫϥυ 18 ؇͔ͳൺֱͷਖ਼ମݟͨΓʂ is_equal_functionzend_compareͱݴ͏ؔʹରԠ͍ͯ͠ΔΑ͏Ͱ͢ɻ /* == ͷॲཧ */ ZEND_API
zend_result ZEND_FASTCALL is_equal_function(zval *result, zval *op1, zval *op2) /* {{{ */ { ZVAL_BOOL(result, zend_compare(op1, op2) == 0); return SUCCESS; } /* }}} */
Copyright© M&AΫϥυ 19 ؇͔ͳൺֱͷਖ਼ମݟͨΓʂ ZEND_API int ZEND_FASTCALL zend_compare(zval *op1, zval
*op2) /* {{{ */ { int converted = 0; zval op1_copy, op2_copy; while (1) { switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) { case TYPE_PAIR(IS_LONG, IS_LONG): return Z_LVAL_P(op1)>Z_LVAL_P(op2)?1:(Z_LVAL_P(op1)<Z_LVAL_P(op2)?-1:0); /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ case TYPE_PAIR(IS_LONG, IS_DOUBLE): return ZEND_NORMALIZE_BOOL((double)Z_LVAL_P(op1) - Z_DVAL_P(op2)); /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ case TYPE_PAIR(IS_ARRAY, IS_ARRAY): return zend_compare_arrays(op1, op2); case TYPE_PAIR(IS_NULL, IS_NULL): /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ case TYPE_PAIR(IS_STRING, IS_STRING): if (Z_STR_P(op1) == Z_STR_P(op2)) { return 0; } return zendi_smart_strcmp(Z_STR_P(op1), Z_STR_P(op2)); /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ default: if (Z_ISREF_P(op1)) { op1 = Z_REFVAL_P(op1); continue; } else if (Z_ISREF_P(op2)) { op2 = Z_REFVAL_P(op2); continue; } if (Z_TYPE_P(op1) == IS_OBJECT && Z_TYPE_P(op2) == IS_OBJECT && Z_OBJ_P(op1) == Z_OBJ_P(op2)) { return 0; } else if (Z_TYPE_P(op1) == IS_OBJECT) { return Z_OBJ_HANDLER_P(op1, compare)(op1, op2); } else if (Z_TYPE_P(op2) == IS_OBJECT) { return Z_OBJ_HANDLER_P(op2, compare)(op1, op2); } if (!converted) { if (Z_TYPE_P(op1) < IS_TRUE) { return zval_is_true(op2) ? -1 : 0; } else if (Z_TYPE_P(op1) == IS_TRUE) { /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ } else { op1 = _zendi_convert_scalar_to_number_silent(op1, &op1_copy); op2 = _zendi_convert_scalar_to_number_silent(op2, &op2_copy); if (EG(exception)) { return 1; /* to stop comparison of arrays */ } converted = 1; } } else if (Z_TYPE_P(op1)==IS_ARRAY) { return 1; } else if (Z_TYPE_P(op2)==IS_ARRAY) { return -1; } else { ZEND_UNREACHABLE(); zend_throw_error(NULL, "Unsupported operand types"); return 1; } } } } /* }}} */ php-src/Zend/zend_operators.c
Copyright© M&AΫϥυ 20 ؇͔ͳൺֱͷਖ਼ମݟͨΓʂ ͍... ͏ͳΜ͔ΠϠͳ༧ײ͕͠·͢Ͷɻ தΛཁ͍ͯ͘͠ͱɺԋࢉࢠͷࠨӈͷΦϖϥϯυͷܕͷΈ߹ΘͤʹԠͯ͡ɺ ྑ͍ײ͡ʹॲཧΛذͯ͠ฦ͍ͯ͠ΔΈ͍ͨͰ͢ɻ ಉ࢜ͷൺֱී௨ʹߦΘΕ͍ͯ·͕͢ɺจࣈྻͷൺֱͳΜ͔͕ؔݺΕͯ·͢ɻ case
TYPE_PAIR(IS_STRING, IS_STRING): if (Z_STR_P(op1) == Z_STR_P(op2)) { return 0; } return zendi_smart_strcmp(Z_STR_P(op1), Z_STR_P(op2)); zendi_smart_strcmpͱݴ͏ո͍͕ؔ͠ݺΕ͍ͯ·͢ɻ ͲΜͳౕ͔ݟͯΈ·͠ΐ͏ɻ
Copyright© M&AΫϥυ 21 zendi_smart_strcmpͱݴ͏ո͍ؔ͠ ZEND_API int ZEND_FASTCALL zendi_smart_strcmp(zend_string *s1, zend_string
*s2) /* {{{ */ { zend_uchar ret1, ret2; int oflow1, oflow2; zend_long lval1 = 0, lval2 = 0; double dval1 = 0.0, dval2 = 0.0; if ((ret1 = is_numeric_string_ex(s1->val, s1->len, &lval1, &dval1, false, &oflow1, NULL)) && (ret2 = is_numeric_string_ex(s2->val, s2->len, &lval2, &dval2, false, &oflow2, NULL))) { #if ZEND_ULONG_MAX == 0xFFFFFFFF if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0. && ((oflow1 == 1 && dval1 > 9007199254740991. /*0x1FFFFFFFFFFFFF*/) || (oflow1 == -1 && dval1 < -9007199254740991.))) { #else if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0.) { #endif /* both values are integers overflown to the same side, and the * double comparison may have resulted in crucial accuracy lost */ goto string_cmp; } if ((ret1 == IS_DOUBLE) || (ret2 == IS_DOUBLE)) { if (ret1 != IS_DOUBLE) { if (oflow2) { /* 2nd operand is integer > LONG_MAX (oflow2==1) or < LONG_MIN (-1) */ return -1 * oflow2; } dval1 = (double) lval1; } else if (ret2 != IS_DOUBLE) { if (oflow1) { return oflow1; } dval2 = (double) lval2; } else if (dval1 == dval2 && !zend_finite(dval1)) { /* Both values overflowed and have the same sign, * so a numeric comparison would be inaccurate */ goto string_cmp; } dval1 = dval1 - dval2; return ZEND_NORMALIZE_BOOL(dval1); } else { /* they both have to be long's */ return lval1 > lval2 ? 1 : (lval1 < lval2 ? -1 : 0); } } else { int strcmp_ret; string_cmp: strcmp_ret = zend_binary_strcmp(s1->val, s1->len, s2->val, s2->len); return ZEND_NORMALIZE_BOOL(strcmp_ret); } } /* }}} */
Copyright© M&AΫϥυ 22 zendi_smart_strcmpͱݴ͏ո͍ؔ͠ ͏͑ʙ ॲཧͷ༰ɺ • ೖྗ͞Εͨจࣈྻ͕ʮͱͯ͠ධՁͰ͖Δ߹ͱͯ͠ѻ͍ൺֱ͢Δʯ • ͱͯ͠ධՁग़དྷͳ͍߹จࣈྻಉ࢜ͷൺֱΛߦ͏
strcmp໋໊ͬͯͳΜͳΜͩ... ͭ·Γstrcmpͱ໊͔ΓͰɺจࣈྻͱͯ͠ҟͳ͍ͬͯͯͱͯ͠߹͍ͬͯΕ true Ͱ͢ɻ ୭ͩ͜ΜͳΫιΈ͍ͨͳ༷ࢥ͍͍ͭͨͭʙ
Copyright© M&AΫϥυ 23 PHPͷ؇͔ͳൺֱͷ࣮ଶ ͜ΕΛ౿·͑ͯ͏ҰίʔυΛݟͯΈ·͠ΐ͏ ιʔείʔυɿ <?php var_dump(0 == '00');
var_dump('00' == '0000'); var_dump('01' == '001'); ग़ྗɿ bool(true) bool(true) bool(true) ͜ΕͰ಄ͷίʔυͷ࣮ߦ݁ՌͷṖ༹͕͚ͨͱࢥ͍·͢ɻ
Copyright© M&AΫϥυ 24 ݫີͳൺֱͷιʔεͲ͜ʁ Zend/zend_operators.cʹ͍·͢ɻ ZEND_API zend_bool ZEND_FASTCALL zend_is_identical(zval *op1,
zval *op2) /* {{{ */ { if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) { return 0; } switch (Z_TYPE_P(op1)) { case IS_NULL: case IS_FALSE: case IS_TRUE: return 1; case IS_LONG: return (Z_LVAL_P(op1) == Z_LVAL_P(op2)); case IS_RESOURCE: return (Z_RES_P(op1) == Z_RES_P(op2)); case IS_DOUBLE: return (Z_DVAL_P(op1) == Z_DVAL_P(op2)); case IS_STRING: return zend_string_equals(Z_STR_P(op1), Z_STR_P(op2)); case IS_ARRAY: return (Z_ARRVAL_P(op1) == Z_ARRVAL_P(op2) || zend_hash_compare(Z_ARRVAL_P(op1), Z_ARRVAL_P(op2), (compare_func_t) hash_zval_identical_function, 1) == 0); case IS_OBJECT: return (Z_OBJ_P(op1) == Z_OBJ_P(op2)); default: return 0; } } /* }}} */
Copyright© M&AΫϥυ 25 ݫີͳൺֱͷιʔεͲ͜ʁ ·ͣ࠷ॳʹܕҧ͍ͰfalseʹͳΓ·͢ɻ ܕ͕Ұக্ͨ͠ͰɺͦΕͧΕͷܕͰγϯϓϧͳൺֱΛ͍ͯ͠·͢ɻ ʮ==ʯͷιʔείʔυΑΓང͔ʹγϯϓϧͰ͢ɻ
Copyright© M&AΫϥυ 26 ͍͞͝ʹ ࣗࠓ·ͰͳΜͱͳ͘Ͱ͔͠ɺཧղͯ͠ͳ͔ͬͨͰ͕͢ɺࠓճͷௐ ࠪͰͲΕ͚ͩةݥͳ͔Α͘ཧղͰ͖·ͨ͠ɻ օ͞ΜPHPͷൺֱԋࢉࢠͬͯݫ֨ͳൺֱΛ͍·͠ΐ͏ɻ
Copyright© M&AΫϥυ ͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠ʂ 27