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 8 になるまでの sort は相当ヤバい
Search
taisuke arase
September 27, 2024
Technology
87
0
Share
PHP 8 になるまでの sort は相当ヤバい
taisuke arase
September 27, 2024
More Decks by taisuke arase
See All by taisuke arase
PHP 9 に備えよ - 動的プロパティ、どうすればいぃ?
taisukearase
0
6.8k
Other Decks in Technology
See All in Technology
自分をひらくと次のチャレンジの敷居が下がる
sudoakiy
5
1.6k
遊びで始めたNew Relic MCP、気づいたらChatOpsなオブザーバビリティボットができてました/From New Relic MCP to a ChatOps Observability Bot
aeonpeople
1
150
互換性のある(らしい)DBへの移行など考えるにあたってたいへんざっくり
sejima
PRO
0
520
SSoT(Single Source of Truth)で「壊して再生」する設計
kawauso
2
410
Zephyr(RTOS)でARMとRISC-Vのコア間通信をしてみた
iotengineer22
0
120
AWS DevOps Agent or Kiro の使いどころを考える_20260402
masakiokuda
0
140
AIエージェント勉強会第3回 エージェンティックAIの時代がやってきた
ymiya55
0
200
TUNA Camp 2026 京都Stage ヒューリスティックアルゴリズム入門
terryu16
0
650
BFCacheを活用して無限スクロールのUX を改善した話
apple_yagi
0
140
ブラックボックス化したMLシステムのVertex AI移行 / mlops_community_62
visional_engineering_and_design
1
260
20260323_データ分析基盤でGeminiを使う話
1210yuichi0
0
210
【Oracle Cloud ウェビナー】データ主権はクラウドで守れるのか?NTTデータ様のOracle Alloyで実現するソブリン対応クラウドの最適解
oracle4engineer
PRO
3
130
Featured
See All Featured
Facilitating Awesome Meetings
lara
57
6.8k
For a Future-Friendly Web
brad_frost
183
10k
Odyssey Design
rkendrick25
PRO
2
560
Java REST API Framework Comparison - PWX 2021
mraible
34
9.2k
Ethics towards AI in product and experience design
skipperchong
2
240
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
231
22k
Future Trends and Review - Lecture 12 - Web Technologies (1019888BNR)
signer
PRO
0
3.3k
Evolving SEO for Evolving Search Engines
ryanjones
0
170
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
10
1.1k
How to Grow Your eCommerce with AI & Automation
katarinadahlin
PRO
1
160
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
10k
The untapped power of vector embeddings
frankvandijk
2
1.6k
Transcript
PHP 8 になるまでの sort は相当ヤバい 2024.09.28 PHP Conference Okinawa 2024
荒瀬 泰輔 #phpcon_okinawa #track_a
荒瀬 泰輔 @at_taisuke PHPer歴 5年くらい サイボウズかき氷部の部長 2024月刊ぺちこん参加 北海道 東京 香川
福岡 沖縄 2
3
沖縄のおすすめかき氷 4
かんな +plus さん 東京の三宿の人気店「和キッチン かんな」の分店 沖縄ならではの食材を使ったかき 氷 写真は「イエロー」 (パッション フルーツとマンゴーのかき氷)
5
avocafe さん アボカド料理店 クリーミーなアボカドはかき氷 にしても美味しい! 写真は「アボカドキャラメルナッ ツ」 6
行きたいお店 天の群星(てぃんのむりぶし) PLUS MINUS 琉冰( Ryu-Pin) 皆さんのおすすめかき氷、沖縄ぜんざいのお店あったら #phpcon_okinawa で教えてください! 7
本題 8
…の前に 9
[悲報 ] タイトル、半分釣りだった 10
結論 数値と文字列をごちゃ混ぜにした配列を sort しようとしている のがヤバい とはいえ PHP 8 より前の比較演算もヤバいのでどっちもヤバい sort
をするならヤバいコードは掃討しましょう 11
Agenda 当初話す予定だったブログ記事の紹介 x でのご指摘を受けての再調査 PHP の比較の挙動 おまけ PHP の比較 true
or false ? クイズ 「数値から始まる文字列」について 12
当初話す予定だったブログ記事の紹介 13
事前にこの場で話す内容をブログ記事に してました 「 CYBOZU SUMMER BLOG FES '24」 という企画で 8/15
に公開 PHP 8 になるまでの sort は相当ヤバい https://zenn.dev/t_arase/articles/0a12bfd6a76e25 当初話す予定だったブログ記事の紹介 14
PHP 7の比較に矛盾が生じてるぞ! <?php // PHP 7.4.33 var_dump(11 < '12'); //
true var_dump('12' < 'a1'); // true var_dump('a1' < 10); // true var_dump(10 < 11); // true 当初話す予定だったブログ記事の紹介 15
当初話す予定だったブログ記事の紹介 https://commons.wikimedia.org/wiki/File:Impossible_staircase.svg より 16
sort の結果もおかしいぞ! <?php $arr1 = [11, 10, '12', 'a1']; sort($arr1);
var_export($arr1); echo PHP_EOL; $arr2 = ['12', 'a1', 11, 10]; sort($arr2); var_export($arr2); echo PHP_EOL; var_dump($arr1 === $arr2); 当初話す予定だったブログ記事の紹介 17
# PHP 7.4.33 array ( 0 => 10, 1 =>
11, 2 => '12', 3 => 'a1', ) array ( 0 => '12', 1 => 'a1', 2 => 10, 3 => 11, ) bool(false) // var_dump($arr1 === $arr2) 当初話す予定だったブログ記事の紹介 18
PHP 8 でこの矛盾が解消されたぞ! <?php // PHP 8.0.0 var_dump(11 < '12');
// true var_dump('12' < 'a1'); // true var_dump('a1' < 10); // false ここが変わった var_dump(10 < 11); // true 当初話す予定だったブログ記事の紹介 19
PHP 8 で比較演算の挙動が変わったため 数値と「数値形式ではない文字列」を比較する際 PHP 7 まで:文字列を数値に変換してから比較 PHP 8 から:数値を文字列に変換してから比較
するようになった 数値と「数値形式の文字列」を比較する際は今まで通り文字列を数値 に変換してから比較する 'hoge' == 0; // true PHP 7.4.33 まで 'hoge' == 0; // false PHP 8.0.0 から 当初話す予定だったブログ記事の紹介 PHP RFC: Saner string to number comparisons https://wiki.php.net/rfc/string_to_number_comparison より 20
sort 順も正しくなった! // PHP 8.0.0 array ( 0 => 10,
1 => 11, 2 => '12', 3 => 'a1', ) array ( 0 => 10, 1 => 11, 2 => '12', 3 => 'a1', ) bool(true) 当初話す予定だったブログ記事の紹介 21
PHP 8 までの sort は相当おかしい! ヨシ! 当初話す予定だったブログ記事の紹介 22
x でのご指摘を受けての再調査 23
記事公開後、コメントをいただきました 文字列と数値混じりの sortができるように変わったと誤解しそう なので、できない例も載せても良いのではと思いました var_dump(11 < '12'); var_dump('12' < '3a');
var_dump('3a' < '4'); var_dump('4' < 11); x でのご指摘を受けての再調査 ぺん! @tompng さんありがとうございました! https://x.com/at_taisuke/status/1824000184231321736 24
確かに PHP 8 でも比較がおかしいよう な …? // PHP 8.0.0 var_dump(11
< '12'); // true var_dump('12' < '3a'); // true var_dump('3a' < '4'); // true var_dump('4' < 11); // true x でのご指摘を受けての再調査 25
$arr1 = [11, '4', '12', '3a']; sort($arr1); var_export($arr1); $arr2 =
['12', '3a', 11, '4']; sort($arr2); var_export($arr2); var_dump($arr1 === $arr2); array ( 0 => '4', 1 => 11, 2 => '12', 3 => '3a', ) array ( 0 => 11, 1 => '12', 2 => '3a', 3 => '4', ) bool(false) x でのご指摘を受けての再調査 26
自分の遭遇した例がたまたま PHP 8 でいい感じになっただけで、 ダメなパターンもある どうしてこういう結果になるのか再度調査しなくては x でのご指摘を受けての再調査 27
PHP の比較の挙動 28
文字列同士の比較 先頭の文字から順に Unicode 値を使い辞書的に比較する 'a' < 'b'; // true 'a'
< 'A'; // false 'a ' < 'a1' // true PHP の比較の挙動 29
おさらい: PHP 8 での比較で変わった点 数値と「数値形式ではない文字列」を比較する際 PHP 7 まで:文字列を数値に変換してから比較 PHP 8
から:数値を文字列に変換してから比較 するようになった 数値と「数値形式の文字列」を比較する際は今まで通り文字列を数値 に変換してから比較する 'hoge' == 0; // true PHP 7.4.33 まで 'hoge' == 0; // false PHP 8.0.0 から PHP の比較の挙動 30
「数値形式の文字列」について PHP には「数値形式の文字列( numeric strings) 」という概念があ る PHP 7.4.33 までは「
0個以上のスペース + 数値」がこれに該当した が、 PHP 8 からは「 0個以上のスペース + 数値 + 0個以上のスペース」に 変更になった // 数値形式の文字列の例 '11' ' 11 ' // 後ろにスペースがあるため、PHP 8 より前ではただの文字列扱いだった '000011' '11.0' '+11.0E0' PHP の比較の挙動 31
コメントをもらった例を見てみる 11 < '12'; // true // 数値と「数値形式の文字列」の比較のため、「数値形式の文字列」を数値として扱う '12' <
'3a'; // true // 文字列同士の比較となり、最初の1文字目の Unicode で比較される '3a' < '4'; // true // 文字列同士の比較となり、最初の1文字目の Unicode で比較される '4' < 11; // true // 数値と「数値形式の文字列」の比較のため、「数値形式の文字列」を数値として扱う 何と比較されるかで、その値が文字列として扱われるか、数値として 扱われるか変わるため、 sort して順番をつけることができない つまりこんな値を sort しようとするのが悪い PHP の比較の挙動 32
結論 数値と文字列をごちゃ混ぜにした配列を sort しようとしている のがヤバい とはいえ PHP 8 より前の比較演算もヤバいのでどっちもヤバい sort
をするならヤバいコードはそーっとしておかずに掃討しまし ょう 33
ここまで話せたらあとはおまけ 34
PHP の比較 true or false ? クイズ 35
全て PHP 8.0.0 以降の結果で考えてください 全部で 4問です PHP の比較 true or
false ? クイズ 36
10 < 11 true or false ? PHP の比較 true
or false ? クイズ 37
true 数値どうしの比較 10 < 11 PHP の比較 true or false
? クイズ 38
1 < '1 ' true or false ? PHP の比較
true or false ? クイズ 39
false 数値と「数値形式の文字列」の比較のため、 「数値形式の文字列」を 数値として扱う 1 < '1 ' PHP の比較
true or false ? クイズ 40
'1a' < 10 true or false ? PHP の比較 true
or false ? クイズ 41
false 文字列どうしの比較となり、数値を文字列として扱い 1文字目から順 に Unicode で比較される '1a' < 10 ちなみに
PHP 7.4.33 までだと '1a' が数値として扱われ、数値どう しの比較になり、 true になる PHP の比較 true or false ? クイズ 42
'123' < '45 ' true or false ? PHP の比較
true or false ? クイズ 43
false 「数値形式の文字列」どうしの比較になり、両方を数値として扱う '123' < '45 ' ちなみに PHP 7.4.33 までだと
'45 ' が文字列として扱われ、最初 の文字の '1' と '4' の比較の結果、 true になる PHP の比較 true or false ? クイズ 44
「数値から始まる文字列」について 45
「数値から始まる文字列」について PHP には「数値から始まる文字列 (leading-numeric strings)」 という概念も存在する 「数値から始まる文字列」は「数値形式の文字列」 + 任意の文字列 で構成される
'123abc' これは比較演算の際にはただの文字列と同じ扱いになる '123' < '45abc' // true 「数値から始まる文字列」について 46
「数値から始まる文字列」について 「数値から始まる文字列」は数値にキャストした場合には「数値形式 の文字列」部分を数値に変換した値になる var_dump((int) '45abc'); // 45 var_dump((int) 'abc45'); //
0 「数値から始まる文字列」は 数値型が宣言されている引数に入れる ことはできない。 function foo(int $i) { var_dump($i); } foo("123 "); // int(123) foo("123abc"); // TypeError 「数値から始まる文字列」について 47
「数値から始まる文字列」かどうかの見 分け方 「数値から始まる文字列」かどうかは数値に足してみて warning が 出るかどうかで判断できる。 ( PHP 8.3 )
var_dump(123 + "123 "); // int(246) var_dump(123 + "123a"); // Warning: A non-numeric value encountered // int(246) 「数値から始まる文字列」について 48
PHP 7.4.33 までの「数値形式の文字列」 PHP 7.4.33 までは、数値の後ろにスペースがある場合は「数値から 始まる文字列」扱いとなっていた。 // PHP 7.4.33
var_dump(123 + "123 "); // Notice: A non well formed numeric value encountered // int(246) 「数値から始まる文字列」について 49
ご清聴ありがとうございました! 50