Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
PHPの緩やかな比較の実態
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
ゆい
April 11, 2022
Programming
1.6k
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
PHPの緩やかな比較の実態
ゆい
April 11, 2022
More Decks by ゆい
See All by ゆい
LaravelでLIKE句のSQLインジェクション対策をする
fyui001
0
3.8k
Other Decks in Programming
See All in Programming
『コードを書く以外の』エンジニアリング〜課金基盤移行プロジェクト推進のためのTips4選
yuriko1211
0
500
ビデオ通話が繋がる0.2秒で何が起きているのか
supurazako
2
150
Claude Team Plan導入・ガイド
tk3fftk
0
200
The Bowling Game- From Imperative to Functional Programming - Part 1
philipschwarz
PRO
0
330
Generative UI & AI-Assistants for Your Angular Solutions
manfredsteyer
PRO
0
110
【やさしく解説 設計編 #0】DDDのコード、読めるのに分からない人へ
panda728
PRO
2
270
Foundation Models frameworkで画像分析
ryodeveloper
1
120
LLMによるContent Moderationの本番運用の裏側と品質担保への挑戦
suikabar
3
850
言語を使う側から、作る側へ。 自作 Lisp で得た新たな気づき。
andpad
0
120
act2-costs.pdf
sumedhbala
0
110
LaravelLive Japan の裏方のすべて — 第188回 PHP勉強会@東京 (2026-06-24)
suguruooki
2
150
「正の参照」と 「負の導出」で組む ハーネスエンジニアリング
cottpan
1
140
Featured
See All Featured
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
55k
Leading Effective Engineering Teams in the AI Era
addyosmani
9
2.1k
Designing for Performance
lara
611
70k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
17k
VelocityConf: Rendering Performance Case Studies
addyosmani
333
25k
The Spectacular Lies of Maps
axbom
PRO
1
860
Everyday Curiosity
cassininazir
0
260
Build your cross-platform service in a week with App Engine
jlugia
234
18k
Ten Tips & Tricks for a 🌱 transition
stuffmc
0
150
The Illustrated Children's Guide to Kubernetes
chrisshort
51
53k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
34
2.8k
Measuring & Analyzing Core Web Vitals
bluesmoon
9
880
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