-
Notifications
You must be signed in to change notification settings - Fork 44
/
Copy pathcomparison.xml
582 lines (554 loc) · 17.1 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
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
<?xml version="1.0" encoding="utf-8"?>
<!-- EN-Revision: e50e79746736dbdfbabe9bd3566793b3ddf38f58 Maintainer: nobody Status: ready -->
<!-- Reviewed: yes -->
<!-- Rev-Revision: e4b889a3e8b9d87ab605aac9bbe85d2c16c69a1b Reviewer: samesch -->
<!-- CREDITS: tzwenny, betz -->
<sect1 xml:id="language.operators.comparison">
<title>Vergleichs-Operatoren</title>
<titleabbrev>Vergleich</titleabbrev>
<simpara>
Vergleichs-Operatoren erlauben es – wie der Name schon sagt – zwei Werte zu
vergleichen. Wenn Sie an Beispielen verschiedener auf Typen bezogener
Vergleiche interessiert sind, können Sie sich die
<link linkend="types.comparisons">PHP Typvergleich-Tabellen</link>
anschauen.
</simpara>
<table>
<title>Vergleichsoperatoren</title>
<tgroup cols="3">
<thead>
<row>
<entry>Beispiel</entry>
<entry>Name</entry>
<entry>Ergebnis</entry>
</row>
</thead>
<tbody>
<row>
<entry>$a == $b</entry>
<entry>Gleich</entry>
<entry>
Gibt &true; zurück, wenn nach der Typumwandlung <varname>$a</varname>
gleich <varname>$b</varname> ist.
</entry>
</row>
<row>
<entry>$a === $b</entry>
<entry>Identisch</entry>
<entry>
Gibt &true; zurück, wenn <varname>$a</varname> gleich
<varname>$b</varname> ist und beide denselben Typ haben.
</entry>
</row>
<row>
<entry>$a != $b</entry>
<entry>Ungleich</entry>
<entry>
Gibt &true; zurück, wenn nach der Typumwandlung <varname>$a</varname>
nicht gleich <varname>$b</varname> ist.
</entry>
</row>
<row>
<entry>$a <> $b</entry>
<entry>Ungleich</entry>
<entry>
Gibt &true; zurück, wenn nach der Typumwandlung <varname>$a</varname>
nicht gleich <varname>$b</varname> ist.
</entry>
</row>
<row>
<entry>$a !== $b</entry>
<entry>Nicht identisch</entry>
<entry>
Gibt &true; zurück, wenn <varname>$a</varname> nicht gleich
<varname>$b</varname> ist, oder wenn beide nicht denselben Typ haben.
</entry>
</row>
<row>
<entry>$a < $b</entry>
<entry>Kleiner als</entry>
<entry>
Gibt &true; zurück, wenn <varname>$a</varname> kleiner als
<varname>$b</varname> ist.
</entry>
</row>
<row>
<entry>$a > $b</entry>
<entry>Größer als</entry>
<entry>
Gibt &true; zurück, wenn <varname>$a</varname> größer als
<varname>$b</varname> ist.
</entry>
</row>
<row>
<entry>$a <= $b</entry>
<entry>Kleiner oder gleich</entry>
<entry>
Gibt &true; zurück, wenn <varname>$a</varname> kleiner oder gleich
<varname>$b</varname> ist.
</entry>
</row>
<row>
<entry>$a >= $b</entry>
<entry>Größer oder gleich</entry>
<entry>
Gibt &true; zurück, wenn <varname>$a</varname> größer oder gleich
<varname>$b</varname> ist.
</entry>
</row>
<row>
<entry>$a <=> $b</entry>
<entry>Raumschiff</entry>
<entry>
Eine Ganzzahl (<type>int</type>), die kleiner als, gleich oder größer
als 0 ist, wenn <varname>$a</varname> kleiner als, gleich oder größer
als <varname>$b</varname> ist.
</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
Falls beide Operanden
<link linkend="language.types.numeric-strings">numerische Zeichenketten</link>
sind oder ein Operand eine Zahl ist und der andere eine
<link linkend="language.types.numeric-strings">numerische Zeichenkette</link>,
dann wird der Vergleich numerisch durchgeführt. Diese Regel gilt ebenfalls
für die <link linkend="control-structures.switch">switch</link>-Anweisung.
Die Typumwandlung wird nicht durchgeführt, wenn der Vergleichsoperator
<literal>===</literal> oder <literal>!==</literal> ist, da hier sowohl der
Typ als auch der Wert verglichen werden.
</para>
<warning>
<para>
Vor PHP 8.0.0 wurde bei einem Vergleich einer Zeichenkette mit einer Zahl
oder einer numerischen Zeichenkette die Zeichenkette vor dem Vergleich in
eine Zahl umgewandelt und der Vergleich numerisch durchgeführt.
<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
// Ganzzahlen
echo 1 <=> 1; // 0
echo 1 <=> 2; // -1
echo 2 <=> 1; // 1
// Gleitkommazahlen
echo 1.5 <=> 1.5; // 0
echo 1.5 <=> 2.5; // -1
echo 2.5 <=> 1.5; // 1
// Zeichenketten
echo "a" <=> "a"; // 0
echo "a" <=> "b"; // -1
echo "b" <=> "a"; // 1
echo "a" <=> "aa"; // -1
echo "zz" <=> "aa"; // 1
// Arrays
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
// Objekte
$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
// nicht nur die Werte werden verglichen; die Schlüssel müssen übereinstimmen
$a = (object) ["a" => "b"];
$b = (object) ["b" => "b"];
echo $a <=> $b; // 1
?>
]]>
</programlisting>
</informalexample>
</para>
<para>
Für die verschiedenen Typen wird der Vergleich gemäß der folgenden Tabelle
durchgeführt (in der angegebenen Reihenfolge).
</para>
<table xml:id="language.operators.comparison.types">
<title>Vergleich mit verschiedenen Typen</title>
<tgroup cols="3">
<thead>
<row>
<entry>Typ des 1. Operanden</entry>
<entry>Typ des 2. Operanden</entry>
<entry>Ergebnis</entry>
</row>
</thead>
<tbody>
<row>
<entry><type>null</type> oder <type>string</type></entry>
<entry><type>string</type></entry>
<entry>
Umwandlung von &null; nach "", dann numerischer oder lexikalischer
Vergleich
</entry>
</row>
<row>
<entry><type>bool</type> oder <type>null</type></entry>
<entry>anything</entry>
<entry>
Umwandlung beider Werte nach <type>bool</type>, dann &false; < &true;
</entry>
</row>
<row>
<entry><type>object</type></entry>
<entry><type>object</type></entry>
<entry>
Eingebaute Klassen können eigene Vergleichsregeln definieren;
verschiedene Klassen können nicht verglichen werden; für den Vergleich
von Objekten derselben Klasse siehe
<link linkend="language.oop5.object-comparison">Objektvergleiche</link>
</entry>
</row>
<row>
<entry><type>string</type>, <type>resource</type>, <type>int</type> oder <type>float</type></entry>
<entry><type>string</type>, <type>resource</type>, <type>int</type> oder <type>float</type></entry>
<entry>
Umwandlung von Zeichenketten und Ressourcen in Zahlen, dann numerischer
Vergleich
</entry>
</row>
<row>
<entry><type>array</type></entry>
<entry><type>array</type></entry>
<entry>
Das Array mit weniger Elementen ist kleiner; wird ein Schlüssel vom
ersten Operanden nicht im zweiten gefunden, dann sind die Arrays nicht
vergleichbar, andernfalls wird Element für Element verglichen (siehe
folgendes Beispiel)
</entry>
</row>
<row>
<entry><type>object</type></entry>
<entry>anything</entry>
<entry><type>object</type> ist immer größer</entry>
</row>
<row>
<entry><type>array</type></entry>
<entry>anything</entry>
<entry><type>array</type> ist immer größer</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
<example>
<title>Boolesche und null-Vergleiche</title>
<programlisting role="php">
<![CDATA[
<?php
// Boolesche Werte und null werden immer als Boolesche Werte verglichen
var_dump(1 == TRUE); // TRUE - dasselbe wie (bool) 1 == TRUE
var_dump(0 == FALSE); // TRUE - dasselbe wie (bool) 0 == FALSE
var_dump(100 < TRUE); // FALSE - dasselbe wie (bool) 100 < TRUE
var_dump(-10 < FALSE);// FALSE - dasselbe wie (bool) -10 < FALSE
var_dump(min(-100, -10, NULL, 10, 100)); // NULL - (bool) NULL < (bool) -100 ist FALSE < TRUE
?>
]]>
</programlisting>
</example>
</para>
<para>
<example>
<title>Umschreibung von Standard-Array-Vergleichen</title>
<programlisting role="php">
<![CDATA[
<?php
// Arrays werden mit den normalen Vergleichsoperatoren sowie dem Raumschiff-Operator wie folgt verglichen
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>Vergleich von Gleitkommazahlen</title>
<para>
Aufgrund der Art wie Gleitkommazahlen (<type>float</type>) intern
dargestellt werden, sollten zwei Gleitkommazahlen nicht auf Gleichheit
getestet werden.
</para>
<para>
Weitere Informationen sind der Dokumantation von <type>float</type> zu
entnehmen.
</para>
</warning>
<note>
<simpara>
Es ist wichtig zu beachten, dass die Typumwandlung von PHP nicht immer
offensichtlich ist, wenn Werte unterschiedlichen Typs verglichen werden,
insbesondere beim Vergleich von &integer;n mit &boolean;s oder &integer;n
mit &string;s. Daher ist es im Allgemeinen in den meisten Fällen ratsam,
<literal>===</literal> und <literal>!==</literal> für Vergleiche zu
verwenden, anstatt <literal>==</literal> und <literal>!=</literal>.
</simpara>
</note>
<sect2 xml:id="language.operators.comparison.incomparable">
<title>Nicht vergleichbare Werte</title>
<simpara>
Während der Identitätsvergleich (<literal>===</literal> und
<literal>!==</literal>) auf beliebige Werte angewendet werden kann, sollten
die anderen Vergleichsoperatoren nur auf vergleichbare Werte angewandt
werden. Wenn nicht vergleichbare Werte verglichen werden, ist das Ergebnis
undefiniert und sollte nicht als verlässlich eingestuft werden.
</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-Operatoren</link></member>
<member><link linkend="language.types">Typen</link></member>
</simplelist>
</para>
</sect2>
<sect2 xml:id="language.operators.comparison.ternary">
<title>Ternärer Operator</title>
<para>
Ein weiterer Vergleichs-Operator ist der "?:" (oder ternäre) Operator.
<example>
<title>Zuweisen eines Standardwerts</title>
<programlisting role="php">
<![CDATA[
<?php
// Beispielanwendung für den ternären Operator
$action = (empty($_POST['action'])) ? 'standard' : $_POST['action'];
// Obiges ist mit dieser if/else-Anweisung identisch
if (empty($_POST['action'])) {
$action = 'standard';
} else {
$action = $_POST['action'];
}
?>
]]>
</programlisting>
</example>
Der Ausdruck <literal>(ausdr1) ? (ausdr2) : (ausdr3)</literal> wird zu
<replaceable>ausdr2</replaceable> ausgewertet, wenn
<replaceable>ausdr1</replaceable> als &true; ausgewertet wird, und zu
<replaceable>ausdr3</replaceable>, wenn <replaceable>ausdr1</replaceable>
zu &false; ausgewertet wird.
</para>
<para>
Beim ternären Operator kann der mittlere Teil weggelassen werden. Der
Ausdruck <literal>(ausdr1) ?: (ausdr3)</literal> wird zum Ergebnis von
<replaceable>ausdr1</replaceable> zurück, wenn
<replaceable>ausdr1</replaceable> zu &true; ausgewertet wird, und zu
<replaceable>ausdr3</replaceable> andernfalls.
<replaceable>ausdr1</replaceable> wird in diesem Fall nur einmal
ausgewertet.
</para>
<note>
<simpara>
Es ist zu beachten, dass der ternäre Operator ein Ausdruck ist und nicht
als Variable, sondern als Wert eines Ausdrucks ausgewertet wird. Dies ist
unbedingt zu berücksichtigen, wenn eine Variable per Referenz
zurückgegeben werden soll. Die Anweisung <literal>return $var == 42 ? $a :
$b;</literal> in einer Funktion, die per Referenz zurückgibt, wird daher
nicht funktionieren und eine Warnung erzeugen.
</simpara>
</note>
<note>
<para>
Es wird empfohlen, die "Verschachtelung" von ternären Ausdrücken zu
vermeiden. Das Verhalten von PHP bei der Verwendung von mehr als einem
nicht einkgeklammerten ternären Operator innerhalb eines einzigen
Ausdrucks ist im Vergleich zu anderen Sprachen nicht eindeutig. In der Tat
wurden ternäre Ausdrücke vor PHP 8.0.0 links-assoziativ (von links nach
rechts) ausgewertet, und nicht rechts-assoziativ wie in den meisten
anderen Programmiersprachen. Die Links-Assoziativität ist seit PHP 7.4.0
veraltet. Seit PHP 8.0.0 ist der ternäre Operator nicht-assoziativ.
<example>
<title>Ungewöhnliches Verhalten des ternären Operators</title>
<programlisting role="php">
<![CDATA[
<?php
// auf den ersten Blick scheint das folgende 'true' auszugeben
echo (true ? 'true' : false ? 't' : 'f');
// allerdings wird vor PHP 8.0.0 tatsächlich 't' ausgegeben
// das kommt daher, dass ternäre Ausdrücke links-assoziativ ausgewertet werden
// das Folgende ist eine augenfälligere Variante desselben Codes wie oben
echo ((true ? 'true' : false) ? 't' : 'f');
// hier kann man sehen, dass der erste Ausdruck zu 'true' ausgewertet wird,
// was wiederum zu (bool) true ausgewertet wird, und daher wird der Wahr-Zweig
// des zweiten ternären Ausdrucks zurückgegeben.
?>
]]>
</programlisting>
</example>
</para>
</note>
<note>
<para>
Die Verkettung von kurzen ternären Operatoren (<literal>?:</literal>) ist
jedoch stabil und verhält sich plausibel. Sie wird zum ersten Argument
ausgewertet, das einen nicht-falschen Wert ergibt. Es ist zu beachten,
dass undefinierte Werte immer noch eine Warnung auslösen.
<example>
<title>Verkettung kurzer ternärer Operatoren</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-Koaleszens-Operator</title>
<para>
Eine weitere nützliche Kurzform eines Operators ist der Operator "??"
(null-Koaleszenz-Operator, etwa: Zuweisungsoperator für die Kombination mit
null).
<example>
<title>Zuweisung eines Standardwerts</title>
<programlisting role="php">
<![CDATA[
<?php
// Beispiel für die Verwendung des null-Koaleszenz-Operators
$action = $_POST['action'] ?? 'standard';
// Obiges ist mit dieser if/else-Anweisung identisch
if (isset($_POST['action'])) {
$action = $_POST['action'];
} else {
$action = 'standard';
}
?>
]]>
</programlisting>
</example>
Der Ausdruck <literal>(ausdr1) ?? (ausdr2)</literal> wird zu
<replaceable>ausdr2</replaceable> ausgewertet, wenn
<replaceable>ausdr1</replaceable> &null; ist, und zu
<replaceable>ausdr1</replaceable> andernfalls.
</para>
<para>
Insbesondere gibt dieser Operator keinen Hinweis und keine Warnung aus,
wenn der Wert auf der linken Seite nicht existiert, genau wie
<function>isset</function>. Dies ist besonders für Array-Schlüssel
nützlich.
</para>
<note>
<simpara>
Es ist zu beachten, dass der null-Koaleszenz-Operator ein Ausdruck ist und
nicht als Variable, sondern als Wert eines Ausdrucks ausgewertet wird.
Dies ist unbedingt zu berücksichtigen, wenn eine Variable per Referenz
zurückgegeben werden soll. Die Anweisung <literal>return $foo ??
$bar;</literal> in einer Funktion, die per Referenz zurückgibt, wird daher
nicht funktionieren, und eine Warnung erzeugen.
</simpara>
</note>
<note>
<para>
Der null-Koaleszenz-Operator hat eine niedrige Priorität. Das heißt, wenn
er mit anderen Operatoren (&zb; Verkettung von Zeichenketten oder
arithmetische Operatoren) kombiniert wird, sind wahrscheinlich Klammern
erforderlich.
</para>
<programlisting role="php">
<![CDATA[
<?php
// Löst die Warnung aus, dass $name undefiniert ist.
print 'Mr. ' . $name ?? 'Anonymous';
// Gibt "Mr. Anonymous" aus
print 'Mr. ' . ($name ?? 'Anonymous');
?>
]]>
</programlisting>
</note>
<note>
<para>
Es ist zu beachten, dass der null-Koaleszenz-Operator einfach
verschachtelt werden kann:
<example>
<title>Verschachtelung des null-Koaleszenz-Operators</title>
<programlisting role="php">
<![CDATA[
<?php
$foo = null;
$bar = null;
$baz = 1;
$qux = 2;
echo $foo ?? $bar ?? $baz ?? $qux; // gibt 1 aus
?>
]]>
</programlisting>
</example>
</para>
</note>
</sect2>
</sect1>