language/types/type-juggling.xml
183439d468314fc3b1a62cf58feb20330922ed11
...
...
@@ -1,65 +1,47 @@
1
1
<?xml version="1.0" encoding="utf-8"?>
2
-
<!-- $Revision$ -->
3
2
<sect1 xml:id="language.types.type-juggling">
4
3
<title>Type Juggling</title>
5
4

6
5
<simpara>
7
-
PHP does not require (or support) explicit type definition in variable
8
-
declaration; a variable's type is determined by the context in which the
9
-
variable is used. That is to say, if a <type>string</type> value is assigned
10
-
to variable <varname>$var</varname>, <varname>$var</varname> becomes a
11
-
<type>string</type>. If an <type>integer</type> value is then assigned to
12
-
<varname>$var</varname>, it becomes an <type>integer</type>.
6
+
PHP does not require explicit type definition in variable declaration.
7
+
In this case, the type of a variable is determined by the value it stores.
8
+
That is to say, if a <type>string</type> is assigned to variable
9
+
<varname>$var</varname>, then <varname>$var</varname> is of type
10
+
<type>string</type>. If afterwards an <type>int</type> value is assigned
11
+
to <varname>$var</varname>, it will be of type <type>int</type>.
13
12
</simpara>
14
13

15
14
<para>
16
-
An example of PHP's automatic type conversion is the addition operator '+'.
17
-
If either operand is a <type>float</type>, then both operands are evaluated as
18
-
<type>float</type>s, and the result will be a <type>float</type>. Otherwise,
19
-
the operands will be interpreted as <type>integer</type>s, and the result will
20
-
also be an <type>integer</type>. Note that this does <emphasis>not</emphasis>
21
-
change the types of the operands themselves; the only change is in how the
22
-
operands are evaluated and what the type of the expression itself is.
15
+
PHP may attempt to convert the type of a value to another automatically
16
+
in certain contexts. The different contexts which exist are:
17
+
<itemizedlist>
18
+
<listitem>
19
+
<simpara>Numeric</simpara>
20
+
</listitem>
21
+
<listitem>
22
+
<simpara>String</simpara>
23
+
</listitem>
24
+
<listitem>
25
+
<simpara>Logical</simpara>
26
+
</listitem>
27
+
<listitem>
28
+
<simpara>Integral and string</simpara>
29
+
</listitem>
30
+
<listitem>
31
+
<simpara>Comparative</simpara>
32
+
</listitem>
33
+
<listitem>
34
+
<simpara>Function</simpara>
35
+
</listitem>
36
+
</itemizedlist>
23
37
</para>
24
38

25
-
<informalexample>
26
-
<programlisting role="php">
27
-
<![CDATA[
28
-
<?php
29
-
$foo = "0"; // $foo is string (ASCII 48)
30
-
$foo += 2; // $foo is now an integer (2)
31
-
$foo = $foo + 1.3; // $foo is now a float (3.3)
32
-
$foo = 5 + "10 Little Piggies"; // $foo is integer (15)
33
-
$foo = 5 + "10 Small Pigs"; // $foo is integer (15)
34
-
?>
35
-
]]>
36
-
<!-- bad example, no real operator (must be used with variable, modifies it too)
37
-
$foo++; // $foo is the string "1" (ASCII 49)
38
-

39
-
TODO: explain ++/- - behaviour with strings
40
-

41
-
examples:
42
-

43
-
++'001' = '002'
44
-
++'abc' = 'abd'
45
-
++'xyz' = 'xza'
46
-
++'9.9' = '9.0'
47
-
++'-3' = '-4'
48
-
- -'9' = 8 (integer!)
49
-
- -'5.5' = '5.5'
50
-
- -'-9' = -10 (integer)
51
-
- -'09' = 8 (integer)
52
-
- -'abc' = 'abc'
53
-

54
-
-->
55
-
</programlisting>
56
-
</informalexample>
57
-

58
-
<simpara>
59
-
If the last two examples above seem odd, see
60
-
<link linkend="language.types.string.conversion">String conversion to
61
-
numbers</link>.
62
-
</simpara>
39
+
<note>
40
+
<simpara>
41
+
When a value needs to be interpreted as a different type, the value itself
42
+
does <emphasis>not</emphasis> change types.
43
+
</simpara>
44
+
</note>
63
45

64
46
<simpara>
65
47
To force a variable to be evaluated as a certain type, see the section on
...
...
@@ -67,111 +49,328 @@ examples:
67
49
type of a variable, see the <function>settype</function> function.
68
50
</simpara>
69
51

70
-
<para>
71
-
To test any of the examples in this section, use the
72
-
<function>var_dump</function> function.
73
-
</para>
52
+
<sect2>
53
+
<title>Numeric contexts</title>
74
54

75
-
<note>
76
-
<para>
77
-
The behaviour of an automatic conversion to <type>array</type> is currently
78
-
undefined.
79
-
</para>
55
+
<simpara>
56
+
This is the context when using an
57
+
<link linkend="language.operators.arithmetic">arithmetical operator</link>.
58
+
</simpara>
59
+

60
+
<simpara>
61
+
In this context if either operand is a <type>float</type> (or not
62
+
interpretable as an <type>int</type>), both operands are interpreted as
63
+
<type>float</type>s, and the result will be a <type>float</type>.
64
+
Otherwise, the operands will be interpreted as <type>int</type>s,
65
+
and the result will also be an <type>int</type>.
66
+
As of PHP 8.0.0, if one of the operands cannot be interpreted a
67
+
<classname>TypeError</classname> is thrown.
68
+
</simpara>
69
+
</sect2>
70
+

71
+
<sect2>
72
+
<title>String contexts</title>
73
+

74
+
<simpara>
75
+
This is the context when using <function>echo</function>,
76
+
<function>print</function>,
77
+
<link linkend="language.types.string.parsing">string interpolation</link>,
78
+
or the string
79
+
<link linkend="language.operators.string">concatenation operator</link>.
80
+
</simpara>
81
+

82
+
<simpara>
83
+
In this context the value will be interpreted as <type>string</type>.
84
+
If the value cannot be interpreted a <classname>TypeError</classname> is thrown.
85
+
Prior to PHP 7.4.0, an <constant>E_RECOVERABLE_ERROR</constant> was raised.
86
+
</simpara>
87
+
</sect2>
88
+

89
+
<sect2>
90
+
<title>Logical contexts</title>
91
+

92
+
<simpara>
93
+
This is the context when using conditional statements, the
94
+
<link linkend="language.operators.comparison.ternary">ternary operator</link>,
95
+
or a <link linkend="language.operators.logical">logical operator</link>.
96
+
</simpara>
97
+

98
+
<simpara>
99
+
In this context the value will be interpreted as <type>bool</type>.
100
+
</simpara>
101
+
</sect2>
102
+

103
+
<sect2>
104
+
<title>Integral and string contexts</title>
105
+

106
+
<simpara>
107
+
This is the context when using
108
+
<link linkend="language.operators.bitwise">bitwise operators</link>.
109
+
</simpara>
110
+

111
+
<simpara>
112
+
In this context if all operands are of type <type>string</type> the result
113
+
will also be a <type>string</type>.
114
+
Otherwise, the operands will be interpreted as <type>int</type>s,
115
+
and the result will also be an <type>int</type>.
116
+
As of PHP 8.0.0, if one of the operands cannot be interpreted a
117
+
<classname>TypeError</classname> is thrown.
118
+
</simpara>
119
+
</sect2>
120
+

121
+
<sect2>
122
+
<title>Comparative contexts</title>
123
+

124
+
<simpara>
125
+
This is the context when using a
126
+
<link linkend="language.operators.comparison">comparison operator</link>.
127
+
</simpara>
128
+

129
+
<simpara>
130
+
The type conversions which occur in this context are explained in the
131
+
Comparison with Various Types
132
+
<link linkend="language.operators.comparison.types">table</link>.
133
+
</simpara>
134
+
</sect2>
135
+

136
+
<sect2 xml:id="language.types.type-juggling.function">
137
+
<title>Function contexts</title>
138
+

139
+
<simpara>
140
+
This is the context when a value is passed to a typed parameter, property,
141
+
or returned from a function which declares a return type.
142
+
</simpara>
80
143

81
144
<para>
82
-
Also, because PHP supports indexing into <type>string</type>s via offsets
83
-
using the same syntax as <type>array</type> indexing, the following example
84
-
holds true for all PHP versions:
145
+
In this context the value must be a value of the type.
146
+
Two exceptions exist, the first one is: if the value is of type
147
+
<type>int</type> and the declared type is <type>float</type>, then the
148
+
integer is converted to a floating point number.
149
+
The second one is: if the declared type is a <emphasis>scalar</emphasis>
150
+
<!-- e.g. An object that implements __toString will pass a string type -->
151
+
type, the value is convertable to a scalar type,
152
+
and the coercive typing mode is active
153
+
(the default), the value may be converted to an accepted scalar value.
154
+
See below for a description of this behaviour.
85
155
</para>
86
156

87
-
<informalexample>
88
-
<programlisting role="php">
157
+
<warning>
158
+
<simpara>
159
+
<link linkend="functions.internal">Internal functions</link>
160
+
automatically coerce &null; to scalar types,
161
+
this behaviour is <emphasis>DEPRECATED</emphasis> as of PHP 8.1.0.
162
+
</simpara>
163
+
</warning>
164
+

165
+
<sect3 xml:id="language.types.type-juggling.function.simple">
166
+
<title>Coercive typing with simple type declarations</title>
167
+
<itemizedlist>
168
+
<listitem>
169
+
<simpara>
170
+
<type>bool</type> type declaration: value is interpreted as <type>bool</type>.
171
+
</simpara>
172
+
</listitem>
173
+
<listitem>
174
+
<simpara>
175
+
<type>int</type> type declaration: value is interpreted as <type>int</type>
176
+
if the conversion is well-defined. For example the string is
177
+
<link linkend="language.types.numeric-strings">numeric</link>.
178
+
</simpara>
179
+
</listitem>
180
+
<listitem>
181
+
<simpara>
182
+
<type>float</type> type declaration: value is interpreted as <type>float</type>
183
+
if the conversion is well-defined. For example the string is
184
+
<link linkend="language.types.numeric-strings">numeric</link>.
185
+
</simpara>
186
+
</listitem>
187
+
<listitem>
188
+
<simpara>
189
+
<type>string</type> type declaration: value is interpreted as <type>string</type>.
190
+
</simpara>
191
+
</listitem>
192
+
</itemizedlist>
193
+
</sect3>
194
+

195
+
<sect3 xml:id="language.types.type-juggling.function.union">
196
+
<title>Coercive typing with union types</title>
197
+
<para>
198
+
When <literal>strict_types</literal> is not enabled, scalar type declarations
199
+
are subject to limited implicit type coercions.
200
+
If the exact type of the value is not part of the union, then the target type
201
+
is chosen in the following order of preference:
202
+

203
+
<orderedlist>
204
+
<listitem>
205
+
<simpara>
206
+
<type>int</type>
207
+
</simpara>
208
+
</listitem>
209
+
<listitem>
210
+
<simpara>
211
+
<type>float</type>
212
+
</simpara>
213
+
</listitem>
214
+
<listitem>
215
+
<simpara>
216
+
<type>string</type>
217
+
</simpara>
218
+
</listitem>
219
+
<listitem>
220
+
<simpara>
221
+
<type>bool</type>
222
+
</simpara>
223
+
</listitem>
224
+
</orderedlist>
225
+

226
+
If the type exists in the union and the value can be coerced to the
227
+
type under PHP's existing type-checking semantics, then the type is chosen.
228
+
Otherwise, the next type is tried.
229
+
</para>
230
+

231
+
<caution>
232
+
<para>
233
+
As an exception, if the value is a string and both int and float are part
234
+
of the union, the preferred type is determined by the existing
235
+
<link linkend="language.types.numeric-strings">numeric string</link>
236
+
semantics.
237
+
For example, for <literal>"42"</literal> <type>int</type> is chosen,
238
+
while for <literal>"42.0"</literal> <type>float</type> is chosen.
239
+
</para>
240
+
</caution>
241
+

242
+
<note>
243
+
<para>
244
+
Types that are not part of the above preference list are not eligible
245
+
targets for implicit coercion. In particular no implicit coercions to
246
+
the <type>null</type>, <type>false</type>, and <type>true</type>
247
+
types occur.
248
+
</para>
249
+
</note>
250
+

251
+
<example>
252
+
<title>Example of types being coerced into a type part of the union</title>
253
+
<programlisting role="php">
89
254
<![CDATA[
90
255
<?php
91
-
$a = 'car'; // $a is a string
92
-
$a[0] = 'b'; // $a is still a string
93
-
echo $a; // bar
256
+
// int|string
257
+
42 --> 42 // exact type
258
+
"42" --> "42" // exact type
259
+
new ObjectWithToString --> "Result of __toString()"
260
+
// object never compatible with int, fall back to string
261
+
42.0 --> 42 // float compatible with int
262
+
42.1 --> 42 // float compatible with int
263
+
1e100 --> "1.0E+100" // float too large for int type, fall back to string
264
+
INF --> "INF" // float too large for int type, fall back to string
265
+
true --> 1 // bool compatible with int
266
+
[] --> TypeError // array not compatible with int or string
267
+

268
+
// int|float|bool
269
+
"45" --> 45 // int numeric string
270
+
"45.0" --> 45.0 // float numeric string
271
+

272
+
"45X" --> true // not numeric string, fall back to bool
273
+
"" --> false // not numeric string, fall back to bool
274
+
"X" --> true // not numeric string, fall back to bool
275
+
[] --> TypeError // array not compatible with int, float or bool
94
276
?>
95
277
]]>
96
-
</programlisting>
97
-
</informalexample>
278
+
</programlisting>
279
+
</example>
280
+
</sect3>
98
281

99
-
<para>
100
-
See the section titled <link linkend="language.types.string.substr">String
101
-
access by character</link> for more information.
102
-
</para>
103
-
</note>
282
+
</sect2>
104
283

105
284
<sect2 xml:id="language.types.typecasting">
106
285
<title>Type Casting</title>
107
286

108
-
<para>
109
-
Type casting in PHP works much as it does in C: the name of the desired type
110
-
is written in parentheses before the variable which is to be cast.
111
-
</para>
287
+
<simpara>
288
+
Type casting converts the value to a chosen type by writing the type within
289
+
parentheses before the value to convert.
290
+
</simpara>
112
291

113
292
<informalexample>
114
293
<programlisting role="php">
115
294
<![CDATA[
116
295
<?php
117
296
$foo = 10; // $foo is an integer
118
-
$bar = (boolean) $foo; // $bar is a boolean
297
+
$bar = (bool) $foo; // $bar is a boolean
119
298
?>
120
299
]]>
121
300
</programlisting>
122
301
</informalexample>
123
302

124
-
<para>
303
+
<simpara>
125
304
The casts allowed are:
126
-
</para>
305
+
</simpara>
127
306

128
-
<itemizedlist>
129
-
<listitem>
130
-
<simpara>(int), (integer) - cast to <type>integer</type></simpara>
131
-
</listitem>
132
-
<listitem>
133
-
<simpara>(bool), (boolean) - cast to <type>boolean</type></simpara>
134
-
</listitem>
135
-
<listitem>
136
-
<simpara>(float), (double), (real) - cast to <type>float</type></simpara>
137
-
</listitem>
138
-
<listitem>
139
-
<simpara>(string) - cast to <type>string</type></simpara>
140
-
</listitem>
141
-
<listitem>
142
-
<simpara>(array) - cast to <type>array</type></simpara>
143
-
</listitem>
144
-
<listitem>
145
-
<simpara>(object) - cast to <type>object</type></simpara>
146
-
</listitem>
147
-
<listitem>
148
-
<simpara>(unset) - cast to <type>NULL</type> (PHP 5)</simpara>
149
-
</listitem>
150
-
</itemizedlist>
307
+
<simplelist>
308
+
<member><literal>(int)</literal> - cast to <type>int</type></member>
309
+
<member><literal>(bool)</literal> - cast to <type>bool</type></member>
310
+
<member><literal>(float)</literal> - cast to <type>float</type></member>
311
+
<member><literal>(string)</literal> - cast to <type>string</type></member>
312
+
<member><literal>(array)</literal> - cast to <type>array</type></member>
313
+
<member><literal>(object)</literal> - cast to <type>object</type></member>
314
+
<member><literal>(unset)</literal> - cast to <type>NULL</type></member>
315
+
</simplelist>
151
316

152
-
<para>
153
-
(binary) casting and b prefix forward support was added in PHP 5.2.1
154
-
</para>
317
+
<note>
318
+
<para>
319
+
<literal>(integer)</literal> is an alias of the <literal>(int)</literal> cast.
320
+
<literal>(boolean)</literal> is an alias of the <literal>(bool)</literal> cast.
321
+
<literal>(binary)</literal> is an alias of the <literal>(string)</literal> cast.
322
+
<literal>(double)</literal> and <literal>(real)</literal> are aliases of
323
+
the <literal>(float)</literal> cast.
324
+
These casts do not use the canonical type name and are not recommended.
325
+
</para>
326
+
</note>
155
327

156
-
<para>
157
-
Note that tabs and spaces are allowed inside the parentheses, so the
158
-
following are functionally equivalent:
159
-
</para>
328
+
<warning>
329
+
<simpara>
330
+
The <literal>(real)</literal> cast alias has been deprecated as of PHP 8.0.0.
331
+
</simpara>
332
+
</warning>
160
333

161
-
<informalexample>
162
-
<programlisting role="php">
334
+
<warning>
335
+
<simpara>
336
+
The <literal>(unset)</literal> cast has been deprecated as of PHP 7.2.0.
337
+
Note that the <literal>(unset)</literal> cast is the same as assigning the
338
+
value <type>NULL</type> to the variable or call.
339
+
The <literal>(unset)</literal> cast is removed as of PHP 8.0.0.
340
+
</simpara>
341
+
</warning>
342
+

343
+
<caution>
344
+
<simpara>
345
+
The <literal>(binary)</literal> cast and <literal>b</literal> prefix exists
346
+
for forward support. Currently <literal>(binary)</literal> and
347
+
<literal>(string)</literal> are identical, however this may change and
348
+
should not be relied upon.
349
+
</simpara>
350
+
</caution>
351
+

352
+
<note>
353
+
<para>
354
+
Whitespaces are ignored within the parentheses of a cast.
355
+
Therefore, the following two casts are equivalent:
356
+
<informalexample>
357
+
<programlisting role="php">
163
358
<![CDATA[
164
359
<?php
165
360
$foo = (int) $bar;
166
361
$foo = ( int ) $bar;
167
362
?>
168
363
]]>
169
-
</programlisting>
364
+
</programlisting>
365
+
</informalexample>
366
+
</para>
367
+
</note>
170
368

171
-
<para>
369
+
<informalexample>
370
+
<simpara>
172
371
Casting literal <type>string</type>s and variables to binary
173
372
<type>string</type>s:
174
-
</para>
373
+
</simpara>
175
374

176
375
<programlisting role="php">
177
376
<![CDATA[
...
...
@@ -183,11 +382,12 @@ $binary = b"binary string";
183
382
</programlisting>
184
383
</informalexample>
185
384

385
+
<!-- TODO Remove or move into string context section? -->
186
386
<note>
187
-
<para>
387
+
<simpara>
188
388
Instead of casting a variable to a <type>string</type>, it is also possible
189
389
to enclose the variable in double quotes.
190
-
</para>
390
+
</simpara>
191
391

192
392
<informalexample>
193
393
<programlisting role="php">
...
...
@@ -210,60 +410,48 @@ if ($fst === $str) {
210
410
<para>
211
411
It may not be obvious exactly what will happen when casting between certain
212
412
types. For more information, see these sections:
413
+
<simplelist>
414
+
<member><link linkend="language.types.boolean.casting">Converting to boolean</link></member>
415
+
<member><link linkend="language.types.integer.casting">Converting to integer</link></member>
416
+
<member><link linkend="language.types.float.casting">Converting to float</link></member>
417
+
<member><link linkend="language.types.string.casting">Converting to string</link></member>
418
+
<member><link linkend="language.types.array.casting">Converting to array</link></member>
419
+
<member><link linkend="language.types.object.casting">Converting to object</link></member>
420
+
<member><link linkend="language.types.resource.casting">Converting to resource</link></member>
421
+
<member><link linkend="language.types.null.casting">Converting to NULL</link></member>
422
+
<member><link linkend="types.comparisons">The type comparison tables</link></member>
423
+
</simplelist>
213
424
</para>
425
+
</sect2>
214
426

215
-
<itemizedlist>
216
-
<listitem>
217
-
<simpara>
218
-
<link linkend="language.types.boolean.casting">Converting to boolean</link>
219
-
</simpara>
220
-
</listitem>
221
-
<listitem>
222
-
<simpara>
223
-
<link linkend="language.types.integer.casting">Converting to integer</link>
224
-
</simpara>
225
-
</listitem>
226
-
<listitem>
227
-
<simpara>
228
-
<link linkend="language.types.float.casting">Converting to float</link>
229
-
</simpara>
230
-
</listitem>
231
-
<listitem>
232
-
<simpara>
233
-
<link linkend="language.types.string.casting">Converting to string</link>
234
-
</simpara>
235
-
</listitem>
236
-
<listitem>
237
-
<simpara>
238
-
<link linkend="language.types.array.casting">Converting to array</link>
239
-
</simpara>
240
-
</listitem>
241
-
<listitem>
242
-
<simpara>
243
-
<link linkend="language.types.object.casting">Converting to object</link>
244
-
</simpara>
245
-
</listitem>
246
-
<listitem>
247
-
<simpara>
248
-
<link linkend="language.types.resource.casting">Converting to
249
-
resource</link>
250
-
</simpara>
251
-
</listitem>
252
-
<listitem>
253
-
<simpara>
254
-
<link linkend="language.types.null.casting">Converting to NULL</link>
255
-
</simpara>
256
-
</listitem>
257
-
<listitem>
258
-
<simpara>
259
-
<link linkend="types.comparisons">The type comparison tables</link>
260
-
</simpara>
261
-
</listitem>
262
-
</itemizedlist>
427
+
<simplesect>
428
+
<note>
429
+
<simpara>
430
+
Because PHP supports indexing into <type>string</type>s via offsets
431
+
using the same syntax as <type>array</type> indexing, the following example
432
+
holds true for all PHP versions:
433
+
</simpara>
263
434

264
-
</sect2>
265
-
</sect1>
435
+
<informalexample>
436
+
<programlisting role="php">
437
+
<![CDATA[
438
+
<?php
439
+
$a = 'car'; // $a is a string
440
+
$a[0] = 'b'; // $a is still a string
441
+
echo $a; // bar
442
+
?>
443
+
]]>
444
+
</programlisting>
445
+
</informalexample>
446
+

447
+
<simpara>
448
+
See the section titled <link linkend="language.types.string.substr">String
449
+
access by character</link> for more information.
450
+
</simpara>
451
+
</note>
452
+
</simplesect>
266
453

454
+
</sect1>
267
455
<!-- Keep this comment at the end of the file
268
456
Local variables:
269
457
mode: sgml
270
458