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
0
48
PHP 8 になるまでの sort は相当ヤバい
taisuke arase
September 27, 2024
Tweet
Share
More Decks by taisuke arase
See All by taisuke arase
PHP 9 に備えよ - 動的プロパティ、どうすればいぃ?
taisukearase
0
4.3k
Other Decks in Technology
See All in Technology
Log Analytics を使った実際の運用 - Sansan Data Hub での取り組み
sansantech
PRO
0
260
貧民的プログラミングのすすめ
kakehashi
PRO
2
340
OCI IAM Identity Domains Entra IDとの認証連携設定手順 / Identity Domain Federation settings with Entra ID
oracle4engineer
PRO
1
1.4k
【Forkwell】「正しく」失敗できるチームを作る──現場のリーダーのための恐怖と不安を乗り越える技術 - FL#83 / A team that can fail correctly by forkwell
i35_267
2
190
Microsoft_20250311_第2回AI_IoT共創ラボ.pdf
iotcomjpadmin
0
130
スクラムというコンフォートゾーンから抜け出そう!プロジェクト全体に目を向けるインセプションデッキ / Inception Deck for seeing the whole project
takaking22
4
370
Amazon Bedrock 2025 年の熱いアップデート (2025/3 時点)
icoxfog417
PRO
3
500
MLflowはどのようにLLMOpsの課題を解決するのか
taka_aki
0
180
人生を左右する「即答」のススメ: 一瞬の判断を間違えないためにするべきこと
takasyou
9
1.3k
「頑張る」を「楽しむ」に変換する技術
tomoyakitaura
10
1.9k
なぜ「Event Sourcing」を選択したのか〜事実に基づくことの重要性〜/Why did we choose "Event Sourcing"?
bitkey
0
100
【Oracle Cloud ウェビナー】【入門&再入門】はじめてのOracle Cloud Infrastructure [+最新情報]
oracle4engineer
PRO
1
120
Featured
See All Featured
4 Signs Your Business is Dying
shpigford
183
22k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
330
21k
Git: the NoSQL Database
bkeepers
PRO
429
65k
The Invisible Side of Design
smashingmag
299
50k
A better future with KSS
kneath
238
17k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
134
33k
Six Lessons from altMBA
skipperchong
27
3.6k
Speed Design
sergeychernyshev
28
830
StorybookのUI Testing Handbookを読んだ
zakiyama
28
5.5k
Building a Scalable Design System with Sketch
lauravandoore
462
33k
Dealing with People You Can't Stand - Big Design 2015
cassininazir
366
25k
The Straight Up "How To Draw Better" Workshop
denniskardys
232
140k
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