-
Notifications
You must be signed in to change notification settings - Fork 79
/
Copy pathcomparison.xml
542 lines (507 loc) · 17.2 KB
/
comparison.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
<!-- EN-Revision: e50e79746736dbdfbabe9bd3566793b3ddf38f58 Maintainer: mumumu Status: ready -->
<sect1 xml:id="language.operators.comparison">
<title>比較演算子</title>
<titleabbrev>比較演算子</titleabbrev>
<simpara>
比較演算子は、その名前が示すように、二つの値を比較します。
<link linkend="types.comparisons">型の比較表</link>
に、型に関連するさまざまな比較の例があります。
</simpara>
<table>
<title>比較演算子</title>
<tgroup cols="3">
<thead>
<row>
<entry>例</entry>
<entry>名前</entry>
<entry>結果</entry>
</row>
</thead>
<tbody>
<row>
<entry>$a == $b</entry>
<entry>等しい</entry>
<entry>型の相互変換をした後で <varname>$a</varname> が <varname>$b</varname> に等しい時に &true;。</entry>
</row>
<row>
<entry>$a === $b</entry>
<entry>等しい</entry>
<entry><varname>$a</varname> が <varname>$b</varname> に等しく、および同じ型である場合に &true; 。
</entry>
</row>
<row>
<entry>$a != $b</entry>
<entry>等しくない</entry>
<entry>型の相互変換をした後で <varname>$a</varname> が <varname>$b</varname> に等しくない場合に &true;。</entry>
</row>
<row>
<entry>$a <> $b</entry>
<entry>等しくない</entry>
<entry>型の相互変換をした後で <varname>$a</varname> が <varname>$b</varname> に等しくない場合に &true;。</entry>
</row>
<row>
<entry>$a !== $b</entry>
<entry>等しくない</entry>
<entry>
<varname>$a</varname> が <varname>$b</varname> と等しくないか、同じ型でない場合に &true; 。
</entry>
</row>
<row>
<entry>$a < $b</entry>
<entry>より少ない</entry>
<entry><varname>$a</varname> が <varname>$b</varname> より少ない時に &true;。</entry>
</row>
<row>
<entry>$a > $b</entry>
<entry>より多い</entry>
<entry><varname>$a</varname> が <varname>$b</varname> より多い時に &true;。</entry>
</row>
<row>
<entry>$a <= $b</entry>
<entry>より少ないか等しい</entry>
<entry><varname>$a</varname> が <varname>$b</varname> より少ないか等しい時に &true;。</entry>
</row>
<row>
<entry>$a >= $b</entry>
<entry>より多いか等しい</entry>
<entry><varname>$a</varname> が <varname>$b</varname> より多いか等しい時に &true;。</entry>
</row>
<row>
<entry>$a <=> $b</entry>
<entry>宇宙船演算子</entry>
<entry>
<varname>$a</varname> が
<varname>$b</varname> より小さい場合は、0より小さい整数。
<varname>$a</varname> が
<varname>$b</varname> と等しい場合は、0。
<varname>$a</varname> が
<varname>$b</varname> より大きい場合は、0より大きい整数。
</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
オペランドが両方
<link linkend="language.types.numeric-strings">数値形式の文字列</link> の場合、
もしくは一方が数値で、もう一方が
<link linkend="language.types.numeric-strings">数値形式の文字列</link> の場合、
比較は数値として行われます。
これらのルールは
<link linkend="control-structures.switch">switch</link> 文にも適用されます。
型の変換は
演算子が <literal>===</literal> や <literal>!==</literal> の場合は行われません。
なぜなら、これらの演算子は、値と型を両方比較するものだからです。
</para>
<warning>
<para>
PHP 8.0.0 より前のバージョンでは、
文字列が数値または数値形式の文字列の場合、文字列は比較する前に数値に変換されていました。
これによって、以下の例で見られるような驚きの結果が生じる場合があります:
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
var_dump(0 == "a");
var_dump("1" == "01");
var_dump("10" == "1e1");
var_dump(100 == "1e2");
switch ("a") {
case 0:
echo "0";
break;
case "a":
echo "a";
break;
}
?>
]]>
</programlisting>
&example.outputs.7;
<screen>
<![CDATA[
bool(true)
bool(true)
bool(true)
bool(true)
0
]]>
</screen>
&example.outputs.8;
<screen>
<![CDATA[
bool(false)
bool(true)
bool(true)
bool(true)
a
]]>
</screen>
</informalexample>
</para>
</warning>
<para>
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
// Integer
echo 1 <=> 1; // 0
echo 1 <=> 2; // -1
echo 2 <=> 1; // 1
// Float
echo 1.5 <=> 1.5; // 0
echo 1.5 <=> 2.5; // -1
echo 2.5 <=> 1.5; // 1
// 文字列
echo "a" <=> "a"; // 0
echo "a" <=> "b"; // -1
echo "b" <=> "a"; // 1
echo "a" <=> "aa"; // -1
echo "zz" <=> "aa"; // 1
// 配列
echo [] <=> []; // 0
echo [1, 2, 3] <=> [1, 2, 3]; // 0
echo [1, 2, 3] <=> []; // 1
echo [1, 2, 3] <=> [1, 2, 1]; // 1
echo [1, 2, 3] <=> [1, 2, 4]; // -1
// オブジェクト
$a = (object) ["a" => "b"];
$b = (object) ["a" => "b"];
echo $a <=> $b; // 0
$a = (object) ["a" => "b"];
$b = (object) ["a" => "c"];
echo $a <=> $b; // -1
$a = (object) ["a" => "c"];
$b = (object) ["a" => "b"];
echo $a <=> $b; // 1
// 比較するのは値だけではない; キーも一致しなければならない
$a = (object) ["a" => "b"];
$b = (object) ["b" => "b"];
echo $a <=> $b; // 1
?>
]]>
</programlisting>
</informalexample>
</para>
<para>
多くの型では、以下の表にしたがって(上から順に)比較が行われます。
</para>
<table xml:id="language.operators.comparison.types">
<title>さまざまな型の比較</title>
<tgroup cols="3">
<thead>
<row>
<entry>第 1 オペランドの型</entry>
<entry>第 2 オペランドの型</entry>
<entry>結果</entry>
</row>
</thead>
<tbody>
<row>
<entry><type>null</type> または <type>string</type></entry>
<entry><type>string</type></entry>
<entry>&null; を "" に変換し、数値または文字として比較します</entry>
</row>
<row>
<entry><type>bool</type> または <type>null</type></entry>
<entry>あらゆる型</entry>
<entry>両辺を <type>bool</type> に変換し、&false; < &true; と判断します</entry>
</row>
<row>
<entry><type>object</type></entry>
<entry><type>object</type></entry>
<entry>組み込みクラスには独自の比較基準が定義されています。
異なるクラスは比較できません。同じクラスであるかどうかは
<link
linkend="language.oop5.object-comparison">ここで説明されています</link>。
</entry>
</row>
<row>
<entry><type>string</type>, <type>resource</type>, <type>int</type> または <type>float</type></entry>
<entry><type>string</type>, <type>resource</type>, <type>int</type> または <type>float</type></entry>
<entry>文字列やリソースを数値に変換し、算術演算を行います</entry>
</row>
<row>
<entry><type>array</type></entry>
<entry><type>array</type></entry>
<entry>要素数の少ない配列のほうが小さくなります。オペランド 1 のキーが
オペランド 2 に存在しない場合、配列は比較できません。そうでない場合は
個々の要素の値を比較します(以下の例を参照ください)</entry>
</row>
<row>
<entry><type>object</type></entry>
<entry>あらゆる型</entry>
<entry><type>object</type> のほうが常に大きくなります</entry>
</row>
<row>
<entry><type>array</type></entry>
<entry>あらゆる型</entry>
<entry><type>array</type> のほうが常に大きくなります</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
<example>
<title>Boolean/null の比較</title>
<programlisting role="php">
<![CDATA[
<?php
// Bool and null are compared as bool always
var_dump(1 == TRUE); // TRUE - same as (bool) 1 == TRUE
var_dump(0 == FALSE); // TRUE - same as (bool) 0 == FALSE
var_dump(100 < TRUE); // FALSE - same as (bool) 100 < TRUE
var_dump(-10 < FALSE);// FALSE - same as (bool) -10 < FALSE
var_dump(min(-100, -10, NULL, 10, 100)); // NULL - (bool) NULL < (bool) -100 is FALSE < TRUE
?>
]]>
</programlisting>
</example>
</para>
<para>
<example>
<title>一般的な配列の比較</title>
<programlisting role="php">
<![CDATA[
<?php
// 標準の比較演算子や、宇宙船演算子を用いて、配列はこのように比較されます
function standard_array_compare($op1, $op2)
{
if (count($op1) < count($op2)) {
return -1; // $op1 < $op2
} elseif (count($op1) > count($op2)) {
return 1; // $op1 > $op2
}
foreach ($op1 as $key => $val) {
if (!array_key_exists($key, $op2)) {
return 1;
} elseif ($val < $op2[$key]) {
return -1;
} elseif ($val > $op2[$key]) {
return 1;
}
}
return 0; // $op1 == $op2
}
?>
]]>
</programlisting>
</example>
</para>
<warning>
<title>浮動小数点数値の比較</title>
<para>
ふたつの <type>float</type> 値が等しいかどうかを調べてはいけません。
<type>float</type> の内部的な表現方法がその理由です。
</para>
<para>
詳細な情報は <type>float</type> のドキュメントを参照ください。
</para>
</warning>
<note>
<simpara>
PHP における型の相互変換の動作は、
異なる型同士を比較する時には必ずしも自明でないことに注意して下さい。
整数型 と boolean を比較したり、
整数型 を 文字列 と比較する場合は特にそうです。
よって一般的には、
<literal>==</literal> や <literal>!=</literal>
ではなく
<literal>===</literal> と <literal>!==</literal>
を使う方がほとんどの場合は好ましいです。
</simpara>
</note>
<sect2 xml:id="language.operators.comparison.incomparable">
<title>比較できない値</title>
<simpara>
(<literal>===</literal> や <literal>!==</literal> を使った)
同一性の比較は、あらゆる値に適用できますが、
それ以外の演算子は、比較できる値同士の場合にのみ適用可能です。
比較できない値同士を比較した場合の結果は未定義であり、
その結果に依存すべきではありません。
</simpara>
</sect2>
<sect2 role="seealso">
&reftitle.seealso;
<para>
<simplelist>
<member><function>strcasecmp</function></member>
<member><function>strcmp</function></member>
<member><link linkend="language.operators.array">Array operators</link></member>
<member><link linkend="language.types">Types</link></member>
</simplelist>
</para>
</sect2>
<sect2 xml:id="language.operators.comparison.ternary">
<title>三項演算子</title>
<para>
もうひとつの条件演算子として "?:"(あるいは三項)演算子があります。
<example>
<title>デフォルト値を設定する</title>
<programlisting role="php">
<![CDATA[
<?php
// 三項演算子の使用例
$action = (empty($_POST['action'])) ? 'default' : $_POST['action'];
// 上記は以下の if/else 式と同じです。
if (empty($_POST['action'])) {
$action = 'default';
} else {
$action = $_POST['action'];
}
?>
]]>
</programlisting>
</example>
<literal>(expr1) ? (expr2) : (expr3)</literal>
という式は、<replaceable>式1</replaceable> が &true; の場合に
<replaceable>式2</replaceable> を、
<replaceable>式1</replaceable> が &false; の場合に
<replaceable>式3</replaceable> を値とします。
</para>
<para>
三項演算子のまんなかの部分をなくすこともできます。
式 <literal>expr1 ?: expr3</literal> の結果は、<replaceable>expr1</replaceable> が
&true; と同等の場合は <replaceable>expr1</replaceable>、
それ以外の場合は <replaceable>expr3</replaceable> となります。
この場合、<replaceable>expr1</replaceable> は一度だけ評価されます。
</para>
<note>
<simpara>
三項演算子は式であり、値としては評価されずに式の結果として評価される
ことに注意してください。演算結果をリファレンスとして返したい場合に、
これを知っておくことが大切です。結果をリファレンスとして返す関数で
<literal>return $var == 42 ? $a : $b;</literal> とすることはできず、
警告が発生します。
</simpara>
</note>
<note>
<para>
三項演算子を "積み重ねて" 使用することは避けましょう。
ひとつの文の中で括弧で囲わずに複数の三項演算子を使用した際の PHP の振る舞いは、
他のプログラミング言語のそれと比べて、少々わかりにくいものです。
PHP 8.0.0 より前のバージョンでは、三項演算子は左から右に評価されていました。
他の殆どのプログラミング言語では、右から左に評価されます。
左から右に評価される振る舞いに依存することは、PHP 7.4.0 以降は推奨されません。
PHP 8.0.0 以降は、三項演算子はどの演算とも結合しなくなっています。
<example>
<title>三項演算子のわかりにくい挙動</title>
<programlisting role="php">
<![CDATA[
<?php
// ぱっと見た感じでは、これは 'true' と表示されると思うでしょう。
echo (true ? 'true' : false ? 't' : 'f');
// しかし、PHP 8.0.0 より前のバージョンでは、実際には上の出力結果は 't' です。
// なぜなら、三項演算子は左結合だったからです。
// 上のコードをもう少しわかりやすく書くと、このようになります。
echo ((true ? 'true' : false) ? 't' : 'f');
// まず、最初の式が 'true' と評価されます。この 'true' は
// (bool) true と評価されるので、それをもとに二番目の三項
// 演算子が評価されます。
?>
]]>
</programlisting>
</example>
</para>
</note>
<note>
<para>
一方で、三項演算子の短縮形の挙動は安定しており、
理にかなった動作をします。
これは、&false; と評価されない最初の引数を評価します。
但し、未定義の値については未だ警告が出るので注意して下さい。
<example>
<title>三項演算子の短縮形</title>
<programlisting role="php">
<![CDATA[
<?php
echo 0 ?: 1 ?: 2 ?: 3, PHP_EOL; //1
echo 0 ?: 0 ?: 2 ?: 3, PHP_EOL; //2
echo 0 ?: 0 ?: 0 ?: 3, PHP_EOL; //3
?>
]]>
</programlisting>
</example>
</para>
</note>
</sect2>
<sect2 xml:id="language.operators.comparison.coalesce">
<title>Null 合体演算子</title>
<para>
別の便利な短縮形式の演算子として、
"??" 演算子 (Null 合体演算子) を使うことが出来ます。
<example>
<title>デフォルト値の代入</title>
<programlisting role="php">
<![CDATA[
<?php
// Null 合体演算子の使用例
$action = $_POST['action'] ?? 'default';
// 上の文は、この if/else 文と同じ意味です
if (isset($_POST['action'])) {
$action = $_POST['action'];
} else {
$action = 'default';
}
?>
]]>
</programlisting>
</example>
式 <literal>(expr1) ?? (expr2)</literal> は、
<replaceable>expr1</replaceable> が &null; である場合は <replaceable>expr2</replaceable>
と評価され、それ以外の場合は <replaceable>expr1</replaceable> と評価されます。
</para>
<para>
この演算子は、左側の値が存在しない場合でも notice や warning が発生しません。
<function>isset</function> と同じ挙動です。
これは、配列のキーを扱う場合に便利です。
</para>
<note>
<simpara>
Null 合体演算子は式であることに注意しましょう。変数として評価されるのではなく、式の結果として評価されます。
変数を参照で返そうとするときには、これを意識しておくことが重要です。
参照返しの関数で <literal>return $foo ?? $bar;</literal> のように書いてもうまく動かずに、
警告が発生します。
</simpara>
</note>
<note>
<para>
Null 合体演算子の優先順位は低いです。
(文字列結合や、算術演算子のような)
他の演算子と組み合わせる場合には、おそらくカッコが必要になるでしょう。
</para>
<programlisting role="php">
<![CDATA[
<?php
// $name が未定義の場合、警告が発生します。
print 'Mr. ' . $name ?? 'Anonymous';
// "Mr. Anonymous" と出力
print 'Mr. ' . ($name ?? 'Anonymous');
?>
]]>
</programlisting>
</note>
<note>
<para>
Null 合体演算子はネストさせることもできます。
<example>
<title>Null 合体演算子のネスト</title>
<programlisting role="php">
<![CDATA[
<?php
$foo = null;
$bar = null;
$baz = 1;
$qux = 2;
echo $foo ?? $bar ?? $baz ?? $qux; // 出力は 1 です
?>
]]>
</programlisting>
</example>
</para>
</note>
</sect2>
</sect1>