mirror of
https://github.com/sigmasternchen/php-doc-en
synced 2025-03-15 16:38:54 +00:00

* document changes to `new` in php 8.0 * document php 8.0 changes for `instanceof` * document php 8.0 change to `define` Co-authored-by: Peter Cowburn <petercowburn@gmail.com> Closes GH-1155.
2798 lines
77 KiB
XML
2798 lines
77 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
|
<!-- $Revision$ -->
|
|
<chapter xml:id="language.operators" xmlns="http://docbook.org/ns/docbook">
|
|
<title>Operators</title>
|
|
<simpara>
|
|
An operator is something that takes one or more values (or
|
|
expressions, in programming jargon) and yields another value (so that the
|
|
construction itself becomes an expression).
|
|
</simpara>
|
|
<para>
|
|
Operators can be grouped according to the number of values they take. Unary
|
|
operators take only one value, for example <literal>!</literal> (the
|
|
<link linkend="language.operators.logical">logical not operator</link>) or
|
|
<literal>++</literal> (the
|
|
<link linkend="language.operators.increment">increment operator</link>).
|
|
Binary operators take two values, such as the familiar
|
|
<link linkend="language.operators.arithmetic">arithmetical operators</link>
|
|
<literal>+</literal> (plus) and <literal>-</literal> (minus), and the
|
|
majority of PHP operators fall into this category. Finally, there is a
|
|
single <link linkend="language.operators.comparison.ternary">ternary
|
|
operator</link>, <literal>? :</literal>, which takes three values; this is
|
|
usually referred to simply as "the ternary operator" (although it could
|
|
perhaps more properly be called the conditional operator).
|
|
</para>
|
|
<para>
|
|
A full list of PHP operators follows in the section
|
|
<link linkend="language.operators.precedence">Operator Precedence</link>.
|
|
The section also explains operator precedence and associativity, which govern
|
|
exactly how expressions containing several different operators are
|
|
evaluated.
|
|
</para>
|
|
|
|
<sect1 xml:id="language.operators.precedence">
|
|
<title>Operator Precedence</title>
|
|
<para>
|
|
The precedence of an operator specifies how "tightly" it binds two
|
|
expressions together. For example, in the expression <literal>1 +
|
|
5 * 3</literal>, the answer is <literal>16</literal> and not
|
|
<literal>18</literal> because the multiplication ("*") operator
|
|
has a higher precedence than the addition ("+") operator.
|
|
Parentheses may be used to force precedence, if necessary. For
|
|
instance: <literal>(1 + 5) * 3</literal> evaluates to
|
|
<literal>18</literal>.
|
|
</para>
|
|
<para>
|
|
When operators have equal precedence their associativity decides
|
|
how the operators are grouped. For example "-" is left-associative, so
|
|
<literal>1 - 2 - 3</literal> is grouped as <literal>(1 - 2) - 3</literal>
|
|
and evaluates to <literal>-4</literal>. "=" on the other hand is
|
|
right-associative, so <literal>$a = $b = $c</literal> is grouped as
|
|
<literal>$a = ($b = $c)</literal>.
|
|
</para>
|
|
<para>
|
|
Operators of equal precedence that are non-associative cannot be used
|
|
next to each other, for example <literal>1 < 2 > 1</literal> is
|
|
illegal in PHP. The expression <literal>1 <= 1 == 1</literal> on the
|
|
other hand is legal, because the <literal>==</literal> operator has a lower
|
|
precedence than the <literal><=</literal> operator.
|
|
</para>
|
|
<para>
|
|
Associativity is only meaningful for binary (and ternary) operators.
|
|
Unary operators are either prefix or postfix so this notion is not applicable.
|
|
For example <literal>!!$a</literal> can only be grouped as <literal>!(!$a)</literal>.
|
|
</para>
|
|
<para>
|
|
Use of parentheses, even when not strictly necessary, can often increase
|
|
readability of the code by making grouping explicit rather than relying
|
|
on the implicit operator precedence and associativity.
|
|
</para>
|
|
<para>
|
|
The following table lists the operators in order of precedence, with
|
|
the highest-precedence ones at the top. Operators on the same line
|
|
have equal precedence, in which case associativity decides grouping.
|
|
<table>
|
|
<title>Operator Precedence</title>
|
|
<tgroup cols="2">
|
|
<thead>
|
|
<row>
|
|
<entry>Associativity</entry>
|
|
<entry>Operators</entry>
|
|
<entry>Additional Information</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry>(n/a)</entry>
|
|
<entry>
|
|
<literal>clone</literal>
|
|
<literal>new</literal>
|
|
</entry>
|
|
<entry><link linkend="language.oop5.cloning">clone</link> and <link linkend="language.oop5.basic.new">new</link></entry>
|
|
</row>
|
|
<row>
|
|
<entry>right</entry>
|
|
<entry><literal>**</literal></entry>
|
|
<entry><link linkend="language.operators.arithmetic">arithmetic</link></entry>
|
|
</row>
|
|
<row>
|
|
<entry>(n/a)</entry>
|
|
<entry>
|
|
<literal>+</literal>
|
|
<literal>-</literal>
|
|
<literal>++</literal>
|
|
<literal>--</literal>
|
|
<literal>~</literal>
|
|
<literal>(int)</literal>
|
|
<literal>(float)</literal>
|
|
<literal>(string)</literal>
|
|
<literal>(array)</literal>
|
|
<literal>(object)</literal>
|
|
<literal>(bool)</literal>
|
|
<literal>@</literal>
|
|
</entry>
|
|
<entry>
|
|
<link linkend="language.operators.arithmetic">arithmetic</link> (unary <literal>+</literal> and <literal>-</literal>),
|
|
<link linkend="language.operators.increment">increment/decrement</link>,
|
|
<link linkend="language.operators.bitwise">bitwise</link>,
|
|
<link linkend="language.types.typecasting">type casting</link>&listendand;
|
|
<link linkend="language.operators.errorcontrol">error control</link>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>left</entry>
|
|
<entry><literal>instanceof</literal></entry>
|
|
<entry>
|
|
<link linkend="language.operators.type">type</link>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>(n/a)</entry>
|
|
<entry><literal>!</literal></entry>
|
|
<entry>
|
|
<link linkend="language.operators.logical">logical</link>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>left</entry>
|
|
<entry>
|
|
<literal>*</literal>
|
|
<literal>/</literal>
|
|
<literal>%</literal>
|
|
</entry>
|
|
<entry>
|
|
<link linkend="language.operators.arithmetic">arithmetic</link>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>left</entry>
|
|
<entry>
|
|
<literal>+</literal>
|
|
<literal>-</literal>
|
|
<literal>.</literal>
|
|
</entry>
|
|
<entry>
|
|
<link linkend="language.operators.arithmetic">arithmetic</link> (binary <literal>+</literal> and <literal>-</literal>),
|
|
<link linkend="language.operators.array">array</link>&listendand;
|
|
<link linkend="language.operators.string">string</link> (<literal>.</literal> prior to PHP 8.0.0)
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>left</entry>
|
|
<entry>
|
|
<literal><<</literal>
|
|
<literal>>></literal>
|
|
</entry>
|
|
<entry>
|
|
<link linkend="language.operators.bitwise">bitwise</link>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>left</entry>
|
|
<entry><literal>.</literal></entry>
|
|
<entry>
|
|
<link linkend="language.operators.string">string</link> (as of PHP 8.0.0)
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>non-associative</entry>
|
|
<entry>
|
|
<literal><</literal>
|
|
<literal><=</literal>
|
|
<literal>></literal>
|
|
<literal>>=</literal>
|
|
</entry>
|
|
<entry>
|
|
<link linkend="language.operators.comparison">comparison</link>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>non-associative</entry>
|
|
<entry>
|
|
<literal>==</literal>
|
|
<literal>!=</literal>
|
|
<literal>===</literal>
|
|
<literal>!==</literal>
|
|
<literal><></literal>
|
|
<literal><=></literal>
|
|
</entry>
|
|
<entry>
|
|
<link linkend="language.operators.comparison">comparison</link>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>left</entry>
|
|
<entry><literal>&</literal></entry>
|
|
<entry>
|
|
<link linkend="language.operators.bitwise">bitwise</link>&listendand;
|
|
<link linkend="language.references">references</link></entry>
|
|
</row>
|
|
<row>
|
|
<entry>left</entry>
|
|
<entry><literal>^</literal></entry>
|
|
<entry>
|
|
<link linkend="language.operators.bitwise">bitwise</link>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>left</entry>
|
|
<entry><literal>|</literal></entry>
|
|
<entry>
|
|
<link linkend="language.operators.bitwise">bitwise</link>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>left</entry>
|
|
<entry><literal>&&</literal></entry>
|
|
<entry>
|
|
<link linkend="language.operators.logical">logical</link>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>left</entry>
|
|
<entry><literal>||</literal></entry>
|
|
<entry>
|
|
<link linkend="language.operators.logical">logical</link>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>right</entry>
|
|
<entry><literal>??</literal></entry>
|
|
<entry>
|
|
<link linkend="language.operators.comparison.coalesce">null coalescing</link>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>non-associative</entry>
|
|
<entry><literal>? :</literal></entry>
|
|
<entry>
|
|
<link linkend="language.operators.comparison.ternary">ternary</link>
|
|
(left-associative prior to PHP 8.0.0)
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>right</entry>
|
|
<entry>
|
|
<literal>=</literal>
|
|
<literal>+=</literal>
|
|
<literal>-=</literal>
|
|
<literal>*=</literal>
|
|
<literal>**=</literal>
|
|
<literal>/=</literal>
|
|
<literal>.=</literal>
|
|
<literal>%=</literal>
|
|
<literal>&=</literal>
|
|
<literal>|=</literal>
|
|
<literal>^=</literal>
|
|
<literal><<=</literal>
|
|
<literal>>>=</literal>
|
|
<literal>??=</literal>
|
|
</entry>
|
|
<entry>
|
|
<link linkend="language.operators.assignment">assignment</link>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>(n/a)</entry>
|
|
<entry><literal>yield from</literal></entry>
|
|
<entry>
|
|
<link linkend="control-structures.yield.from">yield from</link>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>(n/a)</entry>
|
|
<entry><literal>yield</literal></entry>
|
|
<entry>
|
|
<link linkend="control-structures.yield">yield</link>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>(n/a)</entry>
|
|
<entry><literal>print</literal></entry>
|
|
<entry><function>print</function></entry>
|
|
</row>
|
|
<row>
|
|
<entry>left</entry>
|
|
<entry><literal>and</literal></entry>
|
|
<entry>
|
|
<link linkend="language.operators.logical">logical</link>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>left</entry>
|
|
<entry><literal>xor</literal></entry>
|
|
<entry>
|
|
<link linkend="language.operators.logical">logical</link>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>left</entry>
|
|
<entry><literal>or</literal></entry>
|
|
<entry>
|
|
<link linkend="language.operators.logical">logical</link>
|
|
</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
</para>
|
|
<para>
|
|
<example>
|
|
<title>Associativity</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
$a = 3 * 3 % 5; // (3 * 3) % 5 = 4
|
|
// ternary operator associativity differs from C/C++
|
|
$a = true ? 0 : true ? 1 : 2; // (true ? 0 : true) ? 1 : 2 = 2 (prior to PHP 8.0.0)
|
|
|
|
$a = 1;
|
|
$b = 2;
|
|
$a = $b += 3; // $a = ($b += 3) -> $a = 5, $b = 5
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
</para>
|
|
<para>
|
|
Operator precedence and associativity only determine how expressions
|
|
are grouped, they do not specify an order of evaluation. PHP does not
|
|
(in the general case) specify in which order an expression is evaluated
|
|
and code that assumes a specific order of evaluation should be avoided,
|
|
because the behavior can change between versions of PHP or depending on
|
|
the surrounding code.
|
|
<example>
|
|
<title>Undefined order of evaluation</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
$a = 1;
|
|
echo $a + $a++; // may print either 2 or 3
|
|
|
|
$i = 1;
|
|
$array[$i] = $i++; // may set either index 1 or 2
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
<example>
|
|
<title><literal>+</literal>, <literal>-</literal> and <literal>.</literal> have the same precedence (prior to PHP 8.0.0)</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
$x = 4;
|
|
// this line might result in unexpected output:
|
|
echo "x minus one equals " . $x-1 . ", or so I hope\n";
|
|
// because it is evaluated like this line (prior to PHP 8.0.0):
|
|
echo (("x minus one equals " . $x) - 1) . ", or so I hope\n";
|
|
// the desired precedence can be enforced by using parentheses:
|
|
echo "x minus one equals " . ($x-1) . ", or so I hope\n";
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
-1, or so I hope
|
|
-1, or so I hope
|
|
x minus one equals 3, or so I hope
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
</para>
|
|
<note>
|
|
<para>
|
|
Although <literal>=</literal> has a lower precedence than
|
|
most other operators, PHP will still allow expressions
|
|
similar to the following: <literal>if (!$a = foo())</literal>,
|
|
in which case the return value of <literal>foo()</literal> is
|
|
put into <varname>$a</varname>.
|
|
</para>
|
|
</note>
|
|
<sect2 role="changelog">
|
|
&reftitle.changelog;
|
|
<informaltable>
|
|
<tgroup cols="2">
|
|
<thead>
|
|
<row>
|
|
<entry>&Version;</entry>
|
|
<entry>&Description;</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry>8.0.0</entry>
|
|
<entry>
|
|
String concatenation (<literal>.</literal>) now has a lower precedence than
|
|
arithmetic addition/subtraction (<literal>+</literal> and <literal>-</literal>) and
|
|
bitwise shift left/right (<literal><<</literal> and <literal>>></literal>);
|
|
previously it had the same precedence as <literal>+</literal> and <literal>-</literal>
|
|
and a higher precedence than <literal><<</literal> and <literal>>></literal>.
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>8.0.0</entry>
|
|
<entry>
|
|
The ternary operator (<literal>? :</literal>) is non-associative now;
|
|
previously it was left-associative.
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>7.4.0</entry>
|
|
<entry>
|
|
Relying on the precedence of string concatenation (<literal>.</literal>) relative to
|
|
arithmetic addition/subtraction (<literal>+</literal> or <literal>-</literal>) or
|
|
bitwise shift left/right (<literal><<</literal> or <literal>>></literal>),
|
|
i.e. using them together in an unparenthesized expression, is deprecated.
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>7.4.0</entry>
|
|
<entry>
|
|
Relying on left-associativity of the ternary operator (<literal>? :</literal>),
|
|
i.e. nesting multiple unparenthesized ternary operators, is deprecated.
|
|
</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</informaltable>
|
|
</sect2>
|
|
</sect1>
|
|
|
|
<sect1 xml:id="language.operators.arithmetic">
|
|
<title>Arithmetic Operators</title>
|
|
<simpara>
|
|
Remember basic arithmetic from school? These work just
|
|
like those.
|
|
</simpara>
|
|
<table>
|
|
<title>Arithmetic Operators</title>
|
|
<tgroup cols="3">
|
|
<thead>
|
|
<row>
|
|
<entry>Example</entry>
|
|
<entry>Name</entry>
|
|
<entry>Result</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry>+$a</entry>
|
|
<entry>Identity</entry>
|
|
<entry>
|
|
Conversion of <varname>$a</varname> to <type>int</type> or
|
|
<type>float</type> as appropriate.
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>-$a</entry>
|
|
<entry>Negation</entry>
|
|
<entry>Opposite of <varname>$a</varname>.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a + $b</entry>
|
|
<entry>Addition</entry>
|
|
<entry>Sum of <varname>$a</varname> and <varname>$b</varname>.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a - $b</entry>
|
|
<entry>Subtraction</entry>
|
|
<entry>Difference of <varname>$a</varname> and <varname>$b</varname>.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a * $b</entry>
|
|
<entry>Multiplication</entry>
|
|
<entry>Product of <varname>$a</varname> and <varname>$b</varname>.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a / $b</entry>
|
|
<entry>Division</entry>
|
|
<entry>Quotient of <varname>$a</varname> and <varname>$b</varname>.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a % $b</entry>
|
|
<entry>Modulo</entry>
|
|
<entry>Remainder of <varname>$a</varname> divided by <varname>$b</varname>.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a ** $b</entry>
|
|
<entry>Exponentiation</entry>
|
|
<entry>Result of raising <varname>$a</varname> to the <varname>$b</varname>'th power.</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
<simpara>
|
|
The division operator ("/") returns a float value unless the two operands
|
|
are integers (or strings that get converted to integers) and the numbers
|
|
are evenly divisible, in which case an integer value will be returned. For
|
|
integer division, see <function>intdiv</function>.
|
|
</simpara>
|
|
<simpara>
|
|
Operands of modulo are converted to <type>int</type>
|
|
before processing. For floating-point modulo, see
|
|
<function>fmod</function>.
|
|
</simpara>
|
|
<para>
|
|
The result of the modulo operator <literal>%</literal> has the same sign
|
|
as the dividend — that is, the result of <literal>$a % $b</literal>
|
|
will have the same sign as <varname>$a</varname>. For example:
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
|
|
echo (5 % 3)."\n"; // prints 2
|
|
echo (5 % -3)."\n"; // prints 2
|
|
echo (-5 % 3)."\n"; // prints -2
|
|
echo (-5 % -3)."\n"; // prints -2
|
|
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
</para>
|
|
<sect2 role="seealso">
|
|
&reftitle.seealso;
|
|
<para>
|
|
<simplelist>
|
|
<member><link linkend="ref.math">Math functions</link></member>
|
|
</simplelist>
|
|
</para>
|
|
</sect2>
|
|
</sect1>
|
|
|
|
<sect1 xml:id="language.operators.assignment">
|
|
<title>Assignment Operators</title>
|
|
<simpara>
|
|
The basic assignment operator is "=". Your first inclination might
|
|
be to think of this as "equal to". Don't. It really means that the
|
|
left operand gets set to the value of the expression on the
|
|
right (that is, "gets set to").
|
|
</simpara>
|
|
<para>
|
|
The value of an assignment expression is the value assigned. That
|
|
is, the value of "<literal>$a = 3</literal>" is 3. This allows you to do some tricky
|
|
things:
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
|
|
$a = ($b = 4) + 5; // $a is equal to 9 now, and $b has been set to 4.
|
|
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
</para>
|
|
<para>
|
|
In addition to the basic assignment operator, there are "combined
|
|
operators" for all of the <link linkend="language.operators">binary
|
|
arithmetic</link>, array union and string operators that allow you to use a value in an
|
|
expression and then set its value to the result of that expression. For
|
|
example:
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
|
|
$a = 3;
|
|
$a += 5; // sets $a to 8, as if we had said: $a = $a + 5;
|
|
$b = "Hello ";
|
|
$b .= "There!"; // sets $b to "Hello There!", just like $b = $b . "There!";
|
|
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
</para>
|
|
<para>
|
|
Note that the assignment copies the original variable to the new
|
|
one (assignment by value), so changes to one will not affect the
|
|
other. This may also have relevance if you need to copy something
|
|
like a large array inside a tight loop.
|
|
</para>
|
|
<para>
|
|
An exception to the usual assignment by value behaviour within PHP occurs
|
|
with <type>object</type>s, which are assigned by reference.
|
|
Objects may be explicitly copied via the <link
|
|
linkend="language.oop5.cloning">clone</link> keyword.
|
|
</para>
|
|
|
|
<sect2 xml:id="language.operators.assignment.reference">
|
|
<title>Assignment by Reference</title>
|
|
<para>
|
|
Assignment by reference is also supported, using the
|
|
"<computeroutput>$var = &$othervar;</computeroutput>" syntax.
|
|
Assignment by reference means that both variables end up pointing at the
|
|
same data, and nothing is copied anywhere.
|
|
</para>
|
|
<para>
|
|
<example>
|
|
<title>Assigning by reference</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
$a = 3;
|
|
$b = &$a; // $b is a reference to $a
|
|
|
|
print "$a\n"; // prints 3
|
|
print "$b\n"; // prints 3
|
|
|
|
$a = 4; // change $a
|
|
|
|
print "$a\n"; // prints 4
|
|
print "$b\n"; // prints 4 as well, since $b is a reference to $a, which has
|
|
// been changed
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
</para>
|
|
<para>
|
|
The <link linkend="language.oop5.basic.new">new</link>
|
|
operator returns a reference automatically, as such assigning the result of
|
|
<link linkend="language.oop5.basic.new">new</link> by reference is an error.
|
|
</para>
|
|
<para>
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
class C {}
|
|
|
|
$o = &new C;
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
Parse error: syntax error, unexpected 'new' (T_NEW) in …
|
|
]]>
|
|
</screen>
|
|
</informalexample>
|
|
</para>
|
|
<para>
|
|
More information on references and their potential uses can be found in
|
|
the <link linkend="language.references">References Explained</link>
|
|
section of the manual.
|
|
</para>
|
|
</sect2>
|
|
|
|
<sect2 xml:id="language.operators.assignment.arithmetic">
|
|
<title>Arithmetic Assignment Operators</title>
|
|
<informaltable>
|
|
<tgroup cols="3">
|
|
<thead>
|
|
<row>
|
|
<entry>Example</entry>
|
|
<entry>Equivalent</entry>
|
|
<entry>Operation</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry>$a += $b</entry>
|
|
<entry>$a = $a + $b</entry>
|
|
<entry>Addition</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a -= $b</entry>
|
|
<entry>$a = $a - $b</entry>
|
|
<entry>Subtraction</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a *= $b</entry>
|
|
<entry>$a = $a * $b</entry>
|
|
<entry>Multiplication</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a /= $b</entry>
|
|
<entry>$a = $a / $b</entry>
|
|
<entry>Division</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a %= $b</entry>
|
|
<entry>$a = $a % $b</entry>
|
|
<entry>Modulus</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a **= $b</entry>
|
|
<entry>$a = $a ** $b</entry>
|
|
<entry>Exponentiation</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</informaltable>
|
|
</sect2>
|
|
|
|
<sect2 xml:id="language.operators.assignment.bitwise">
|
|
<title>Bitwise Assignment Operators</title>
|
|
<informaltable>
|
|
<tgroup cols="3">
|
|
<thead>
|
|
<row>
|
|
<entry>Example</entry>
|
|
<entry>Equivalent</entry>
|
|
<entry>Operation</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry>$a &= $b</entry>
|
|
<entry>$a = $a & $b</entry>
|
|
<entry>Bitwise And</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a |= $b</entry>
|
|
<entry>$a = $a | $b</entry>
|
|
<entry>Bitwise Or</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a ^= $b</entry>
|
|
<entry>$a = $a ^ $b</entry>
|
|
<entry>Bitwise Xor</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a <<= $b</entry>
|
|
<entry>$a = $a << $b</entry>
|
|
<entry>Left Shift</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a >>= $b</entry>
|
|
<entry>$a = $a >> $b</entry>
|
|
<entry>Right Shift</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</informaltable>
|
|
</sect2>
|
|
|
|
<sect2 xml:id="language.operators.assignment.other">
|
|
<title>Other Assignment Operators</title>
|
|
<informaltable>
|
|
<tgroup cols="3">
|
|
<thead>
|
|
<row>
|
|
<entry>Example</entry>
|
|
<entry>Equivalent</entry>
|
|
<entry>Operation</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry>$a .= $b</entry>
|
|
<entry>$a = $a . $b</entry>
|
|
<entry>String Concatenation</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a ??= $b</entry>
|
|
<entry>$a = $a ?? $b</entry>
|
|
<entry>Null Coalesce</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</informaltable>
|
|
</sect2>
|
|
|
|
<sect2 role="seealso" xml:id="language.operators.assignment.see-also">
|
|
&reftitle.seealso;
|
|
<para>
|
|
<simplelist>
|
|
<member><link linkend="language.operators.arithmetic">arithmetic operators</link></member>
|
|
<member><link linkend="language.operators.bitwise">bitwise operators</link></member>
|
|
<member><link linkend="language.operators.comparison.coalesce">null coalescing operator</link></member>
|
|
</simplelist>
|
|
</para>
|
|
</sect2>
|
|
</sect1>
|
|
|
|
<sect1 xml:id="language.operators.bitwise">
|
|
<title>Bitwise Operators</title>
|
|
<simpara>
|
|
Bitwise operators allow evaluation and manipulation of specific
|
|
bits within an integer.
|
|
</simpara>
|
|
<table>
|
|
<title>Bitwise Operators</title>
|
|
<tgroup cols="3">
|
|
<thead>
|
|
<row>
|
|
<entry>Example</entry>
|
|
<entry>Name</entry>
|
|
<entry>Result</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry><userinput>$a & $b</userinput></entry>
|
|
<entry>And</entry>
|
|
<entry>Bits that are set in both <varname>$a</varname> and <varname>$b</varname> are set.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><userinput>$a | $b</userinput></entry>
|
|
<entry>Or (inclusive or)</entry>
|
|
<entry>Bits that are set in either <varname>$a</varname> or <varname>$b</varname> are set.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><userinput>$a ^ $b</userinput></entry>
|
|
<entry>Xor (exclusive or)</entry>
|
|
<entry>
|
|
Bits that are set in <varname>$a</varname> or <varname>$b</varname> but not both are set.
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry><userinput>~ $a</userinput></entry>
|
|
<entry>Not</entry>
|
|
<entry>
|
|
Bits that are set in <varname>$a</varname> are not set, and vice versa.
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry><userinput>$a << $b</userinput></entry>
|
|
<entry>Shift left</entry>
|
|
<entry>
|
|
Shift the bits of <varname>$a</varname> <varname>$b</varname> steps to the left (each step means
|
|
"multiply by two")
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry><userinput>$a >> $b</userinput></entry>
|
|
<entry>Shift right</entry>
|
|
<entry>
|
|
Shift the bits of <varname>$a</varname> <varname>$b</varname> steps to the right (each step means
|
|
"divide by two")
|
|
</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
<para>
|
|
Bit shifting in PHP is arithmetic.
|
|
Bits shifted off either end are discarded.
|
|
Left shifts have zeros shifted in on the right while the sign
|
|
bit is shifted out on the left, meaning the sign of an operand
|
|
is not preserved.
|
|
Right shifts have copies of the sign bit shifted in on the left,
|
|
meaning the sign of an operand is preserved.
|
|
</para>
|
|
<para>
|
|
Use parentheses to ensure the desired
|
|
<link linkend="language.operators.precedence">precedence</link>.
|
|
For example, <literal>$a & $b == true</literal> evaluates
|
|
the equivalency then the bitwise and; while
|
|
<literal>($a & $b) == true</literal> evaluates the bitwise and
|
|
then the equivalency.
|
|
</para>
|
|
<para>
|
|
If both operands for the <literal>&</literal>, <literal>|</literal> and
|
|
<literal>^</literal> operators are strings, then the operation will be
|
|
performed on the ASCII values of the characters that make up the strings and
|
|
the result will be a string. In all other cases, both operands will be
|
|
<link linkend="language.types.integer.casting">converted to integers</link>
|
|
and the result will be an integer.
|
|
</para>
|
|
<para>
|
|
If the operand for the <literal>~</literal> operator is a string, the
|
|
operation will be performed on the ASCII values of the characters that make
|
|
up the string and the result will be a string, otherwise the operand and the
|
|
result will be treated as integers.
|
|
</para>
|
|
<para>
|
|
Both operands and the result for the <literal><<</literal> and
|
|
<literal>>></literal> operators are always treated as integers.
|
|
</para>
|
|
<para>
|
|
<informalexample>
|
|
<para>
|
|
<literallayout>
|
|
PHP's error_reporting ini setting uses bitwise values,
|
|
providing a real-world demonstration of turning
|
|
bits off. To show all errors, except for notices,
|
|
the php.ini file instructions say to use:
|
|
<userinput>E_ALL & ~E_NOTICE</userinput>
|
|
</literallayout>
|
|
</para>
|
|
<para>
|
|
<literallayout>
|
|
This works by starting with E_ALL:
|
|
<computeroutput>00000000000000000111011111111111</computeroutput>
|
|
Then taking the value of E_NOTICE...
|
|
<computeroutput>00000000000000000000000000001000</computeroutput>
|
|
... and inverting it via <literal>~</literal>:
|
|
<computeroutput>11111111111111111111111111110111</computeroutput>
|
|
Finally, it uses AND (&) to find the bits turned
|
|
on in both values:
|
|
<computeroutput>00000000000000000111011111110111</computeroutput>
|
|
</literallayout>
|
|
</para>
|
|
<para>
|
|
<literallayout>
|
|
Another way to accomplish that is using XOR (<literal>^</literal>)
|
|
to find bits that are on in only one value or the other:
|
|
<userinput>E_ALL ^ E_NOTICE</userinput>
|
|
</literallayout>
|
|
</para>
|
|
</informalexample>
|
|
</para>
|
|
<para>
|
|
<informalexample>
|
|
<para>
|
|
<literallayout>
|
|
error_reporting can also be used to demonstrate turning bits on.
|
|
The way to show just errors and recoverable errors is:
|
|
<userinput>E_ERROR | E_RECOVERABLE_ERROR</userinput>
|
|
</literallayout>
|
|
</para>
|
|
<para>
|
|
<literallayout>
|
|
This process combines E_ERROR
|
|
<computeroutput>00000000000000000000000000000001</computeroutput>
|
|
and
|
|
<computeroutput>00000000000000000001000000000000</computeroutput>
|
|
using the OR (<literal>|</literal>) operator
|
|
to get the bits turned on in either value:
|
|
<computeroutput>00000000000000000001000000000001</computeroutput>
|
|
</literallayout>
|
|
</para>
|
|
</informalexample>
|
|
</para>
|
|
<para>
|
|
<example>
|
|
<title>Bitwise AND, OR and XOR operations on integers</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
/*
|
|
* Ignore the top section,
|
|
* it is just formatting to make output clearer.
|
|
*/
|
|
|
|
$format = '(%1$2d = %1$04b) = (%2$2d = %2$04b)'
|
|
. ' %3$s (%4$2d = %4$04b)' . "\n";
|
|
|
|
echo <<<EOH
|
|
--------- --------- -- ---------
|
|
result value op test
|
|
--------- --------- -- ---------
|
|
EOH;
|
|
|
|
|
|
/*
|
|
* Here are the examples.
|
|
*/
|
|
|
|
$values = array(0, 1, 2, 4, 8);
|
|
$test = 1 + 4;
|
|
|
|
echo "\n Bitwise AND \n";
|
|
foreach ($values as $value) {
|
|
$result = $value & $test;
|
|
printf($format, $result, $value, '&', $test);
|
|
}
|
|
|
|
echo "\n Bitwise Inclusive OR \n";
|
|
foreach ($values as $value) {
|
|
$result = $value | $test;
|
|
printf($format, $result, $value, '|', $test);
|
|
}
|
|
|
|
echo "\n Bitwise Exclusive OR (XOR) \n";
|
|
foreach ($values as $value) {
|
|
$result = $value ^ $test;
|
|
printf($format, $result, $value, '^', $test);
|
|
}
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
--------- --------- -- ---------
|
|
result value op test
|
|
--------- --------- -- ---------
|
|
Bitwise AND
|
|
( 0 = 0000) = ( 0 = 0000) & ( 5 = 0101)
|
|
( 1 = 0001) = ( 1 = 0001) & ( 5 = 0101)
|
|
( 0 = 0000) = ( 2 = 0010) & ( 5 = 0101)
|
|
( 4 = 0100) = ( 4 = 0100) & ( 5 = 0101)
|
|
( 0 = 0000) = ( 8 = 1000) & ( 5 = 0101)
|
|
|
|
Bitwise Inclusive OR
|
|
( 5 = 0101) = ( 0 = 0000) | ( 5 = 0101)
|
|
( 5 = 0101) = ( 1 = 0001) | ( 5 = 0101)
|
|
( 7 = 0111) = ( 2 = 0010) | ( 5 = 0101)
|
|
( 5 = 0101) = ( 4 = 0100) | ( 5 = 0101)
|
|
(13 = 1101) = ( 8 = 1000) | ( 5 = 0101)
|
|
|
|
Bitwise Exclusive OR (XOR)
|
|
( 5 = 0101) = ( 0 = 0000) ^ ( 5 = 0101)
|
|
( 4 = 0100) = ( 1 = 0001) ^ ( 5 = 0101)
|
|
( 7 = 0111) = ( 2 = 0010) ^ ( 5 = 0101)
|
|
( 1 = 0001) = ( 4 = 0100) ^ ( 5 = 0101)
|
|
(13 = 1101) = ( 8 = 1000) ^ ( 5 = 0101)
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
</para>
|
|
<para>
|
|
<example>
|
|
<title>Bitwise XOR operations on strings</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
echo 12 ^ 9; // Outputs '5'
|
|
|
|
echo "12" ^ "9"; // Outputs the Backspace character (ascii 8)
|
|
// ('1' (ascii 49)) ^ ('9' (ascii 57)) = #8
|
|
|
|
echo "hallo" ^ "hello"; // Outputs the ascii values #0 #4 #0 #0 #0
|
|
// 'a' ^ 'e' = #4
|
|
|
|
echo 2 ^ "3"; // Outputs 1
|
|
// 2 ^ ((int)"3") == 1
|
|
|
|
echo "2" ^ 3; // Outputs 1
|
|
// ((int)"2") ^ 3 == 1
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
</para>
|
|
<para>
|
|
<example>
|
|
<title>Bit shifting on integers</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
/*
|
|
* Here are the examples.
|
|
*/
|
|
|
|
echo "\n--- BIT SHIFT RIGHT ON POSITIVE INTEGERS ---\n";
|
|
|
|
$val = 4;
|
|
$places = 1;
|
|
$res = $val >> $places;
|
|
p($res, $val, '>>', $places, 'copy of sign bit shifted into left side');
|
|
|
|
$val = 4;
|
|
$places = 2;
|
|
$res = $val >> $places;
|
|
p($res, $val, '>>', $places);
|
|
|
|
$val = 4;
|
|
$places = 3;
|
|
$res = $val >> $places;
|
|
p($res, $val, '>>', $places, 'bits shift out right side');
|
|
|
|
$val = 4;
|
|
$places = 4;
|
|
$res = $val >> $places;
|
|
p($res, $val, '>>', $places, 'same result as above; can not shift beyond 0');
|
|
|
|
|
|
echo "\n--- BIT SHIFT RIGHT ON NEGATIVE INTEGERS ---\n";
|
|
|
|
$val = -4;
|
|
$places = 1;
|
|
$res = $val >> $places;
|
|
p($res, $val, '>>', $places, 'copy of sign bit shifted into left side');
|
|
|
|
$val = -4;
|
|
$places = 2;
|
|
$res = $val >> $places;
|
|
p($res, $val, '>>', $places, 'bits shift out right side');
|
|
|
|
$val = -4;
|
|
$places = 3;
|
|
$res = $val >> $places;
|
|
p($res, $val, '>>', $places, 'same result as above; can not shift beyond -1');
|
|
|
|
|
|
echo "\n--- BIT SHIFT LEFT ON POSITIVE INTEGERS ---\n";
|
|
|
|
$val = 4;
|
|
$places = 1;
|
|
$res = $val << $places;
|
|
p($res, $val, '<<', $places, 'zeros fill in right side');
|
|
|
|
$val = 4;
|
|
$places = (PHP_INT_SIZE * 8) - 4;
|
|
$res = $val << $places;
|
|
p($res, $val, '<<', $places);
|
|
|
|
$val = 4;
|
|
$places = (PHP_INT_SIZE * 8) - 3;
|
|
$res = $val << $places;
|
|
p($res, $val, '<<', $places, 'sign bits get shifted out');
|
|
|
|
$val = 4;
|
|
$places = (PHP_INT_SIZE * 8) - 2;
|
|
$res = $val << $places;
|
|
p($res, $val, '<<', $places, 'bits shift out left side');
|
|
|
|
|
|
echo "\n--- BIT SHIFT LEFT ON NEGATIVE INTEGERS ---\n";
|
|
|
|
$val = -4;
|
|
$places = 1;
|
|
$res = $val << $places;
|
|
p($res, $val, '<<', $places, 'zeros fill in right side');
|
|
|
|
$val = -4;
|
|
$places = (PHP_INT_SIZE * 8) - 3;
|
|
$res = $val << $places;
|
|
p($res, $val, '<<', $places);
|
|
|
|
$val = -4;
|
|
$places = (PHP_INT_SIZE * 8) - 2;
|
|
$res = $val << $places;
|
|
p($res, $val, '<<', $places, 'bits shift out left side, including sign bit');
|
|
|
|
|
|
/*
|
|
* Ignore this bottom section,
|
|
* it is just formatting to make output clearer.
|
|
*/
|
|
|
|
function p($res, $val, $op, $places, $note = '') {
|
|
$format = '%0' . (PHP_INT_SIZE * 8) . "b\n";
|
|
|
|
printf("Expression: %d = %d %s %d\n", $res, $val, $op, $places);
|
|
|
|
echo " Decimal:\n";
|
|
printf(" val=%d\n", $val);
|
|
printf(" res=%d\n", $res);
|
|
|
|
echo " Binary:\n";
|
|
printf(' val=' . $format, $val);
|
|
printf(' res=' . $format, $res);
|
|
|
|
if ($note) {
|
|
echo " NOTE: $note\n";
|
|
}
|
|
|
|
echo "\n";
|
|
}
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs.32bit;
|
|
<screen>
|
|
<![CDATA[
|
|
|
|
--- BIT SHIFT RIGHT ON POSITIVE INTEGERS ---
|
|
Expression: 2 = 4 >> 1
|
|
Decimal:
|
|
val=4
|
|
res=2
|
|
Binary:
|
|
val=00000000000000000000000000000100
|
|
res=00000000000000000000000000000010
|
|
NOTE: copy of sign bit shifted into left side
|
|
|
|
Expression: 1 = 4 >> 2
|
|
Decimal:
|
|
val=4
|
|
res=1
|
|
Binary:
|
|
val=00000000000000000000000000000100
|
|
res=00000000000000000000000000000001
|
|
|
|
Expression: 0 = 4 >> 3
|
|
Decimal:
|
|
val=4
|
|
res=0
|
|
Binary:
|
|
val=00000000000000000000000000000100
|
|
res=00000000000000000000000000000000
|
|
NOTE: bits shift out right side
|
|
|
|
Expression: 0 = 4 >> 4
|
|
Decimal:
|
|
val=4
|
|
res=0
|
|
Binary:
|
|
val=00000000000000000000000000000100
|
|
res=00000000000000000000000000000000
|
|
NOTE: same result as above; can not shift beyond 0
|
|
|
|
|
|
--- BIT SHIFT RIGHT ON NEGATIVE INTEGERS ---
|
|
Expression: -2 = -4 >> 1
|
|
Decimal:
|
|
val=-4
|
|
res=-2
|
|
Binary:
|
|
val=11111111111111111111111111111100
|
|
res=11111111111111111111111111111110
|
|
NOTE: copy of sign bit shifted into left side
|
|
|
|
Expression: -1 = -4 >> 2
|
|
Decimal:
|
|
val=-4
|
|
res=-1
|
|
Binary:
|
|
val=11111111111111111111111111111100
|
|
res=11111111111111111111111111111111
|
|
NOTE: bits shift out right side
|
|
|
|
Expression: -1 = -4 >> 3
|
|
Decimal:
|
|
val=-4
|
|
res=-1
|
|
Binary:
|
|
val=11111111111111111111111111111100
|
|
res=11111111111111111111111111111111
|
|
NOTE: same result as above; can not shift beyond -1
|
|
|
|
|
|
--- BIT SHIFT LEFT ON POSITIVE INTEGERS ---
|
|
Expression: 8 = 4 << 1
|
|
Decimal:
|
|
val=4
|
|
res=8
|
|
Binary:
|
|
val=00000000000000000000000000000100
|
|
res=00000000000000000000000000001000
|
|
NOTE: zeros fill in right side
|
|
|
|
Expression: 1073741824 = 4 << 28
|
|
Decimal:
|
|
val=4
|
|
res=1073741824
|
|
Binary:
|
|
val=00000000000000000000000000000100
|
|
res=01000000000000000000000000000000
|
|
|
|
Expression: -2147483648 = 4 << 29
|
|
Decimal:
|
|
val=4
|
|
res=-2147483648
|
|
Binary:
|
|
val=00000000000000000000000000000100
|
|
res=10000000000000000000000000000000
|
|
NOTE: sign bits get shifted out
|
|
|
|
Expression: 0 = 4 << 30
|
|
Decimal:
|
|
val=4
|
|
res=0
|
|
Binary:
|
|
val=00000000000000000000000000000100
|
|
res=00000000000000000000000000000000
|
|
NOTE: bits shift out left side
|
|
|
|
|
|
--- BIT SHIFT LEFT ON NEGATIVE INTEGERS ---
|
|
Expression: -8 = -4 << 1
|
|
Decimal:
|
|
val=-4
|
|
res=-8
|
|
Binary:
|
|
val=11111111111111111111111111111100
|
|
res=11111111111111111111111111111000
|
|
NOTE: zeros fill in right side
|
|
|
|
Expression: -2147483648 = -4 << 29
|
|
Decimal:
|
|
val=-4
|
|
res=-2147483648
|
|
Binary:
|
|
val=11111111111111111111111111111100
|
|
res=10000000000000000000000000000000
|
|
|
|
Expression: 0 = -4 << 30
|
|
Decimal:
|
|
val=-4
|
|
res=0
|
|
Binary:
|
|
val=11111111111111111111111111111100
|
|
res=00000000000000000000000000000000
|
|
NOTE: bits shift out left side, including sign bit
|
|
]]>
|
|
</screen>
|
|
&example.outputs.64bit;
|
|
<screen>
|
|
<![CDATA[
|
|
|
|
--- BIT SHIFT RIGHT ON POSITIVE INTEGERS ---
|
|
Expression: 2 = 4 >> 1
|
|
Decimal:
|
|
val=4
|
|
res=2
|
|
Binary:
|
|
val=0000000000000000000000000000000000000000000000000000000000000100
|
|
res=0000000000000000000000000000000000000000000000000000000000000010
|
|
NOTE: copy of sign bit shifted into left side
|
|
|
|
Expression: 1 = 4 >> 2
|
|
Decimal:
|
|
val=4
|
|
res=1
|
|
Binary:
|
|
val=0000000000000000000000000000000000000000000000000000000000000100
|
|
res=0000000000000000000000000000000000000000000000000000000000000001
|
|
|
|
Expression: 0 = 4 >> 3
|
|
Decimal:
|
|
val=4
|
|
res=0
|
|
Binary:
|
|
val=0000000000000000000000000000000000000000000000000000000000000100
|
|
res=0000000000000000000000000000000000000000000000000000000000000000
|
|
NOTE: bits shift out right side
|
|
|
|
Expression: 0 = 4 >> 4
|
|
Decimal:
|
|
val=4
|
|
res=0
|
|
Binary:
|
|
val=0000000000000000000000000000000000000000000000000000000000000100
|
|
res=0000000000000000000000000000000000000000000000000000000000000000
|
|
NOTE: same result as above; can not shift beyond 0
|
|
|
|
|
|
--- BIT SHIFT RIGHT ON NEGATIVE INTEGERS ---
|
|
Expression: -2 = -4 >> 1
|
|
Decimal:
|
|
val=-4
|
|
res=-2
|
|
Binary:
|
|
val=1111111111111111111111111111111111111111111111111111111111111100
|
|
res=1111111111111111111111111111111111111111111111111111111111111110
|
|
NOTE: copy of sign bit shifted into left side
|
|
|
|
Expression: -1 = -4 >> 2
|
|
Decimal:
|
|
val=-4
|
|
res=-1
|
|
Binary:
|
|
val=1111111111111111111111111111111111111111111111111111111111111100
|
|
res=1111111111111111111111111111111111111111111111111111111111111111
|
|
NOTE: bits shift out right side
|
|
|
|
Expression: -1 = -4 >> 3
|
|
Decimal:
|
|
val=-4
|
|
res=-1
|
|
Binary:
|
|
val=1111111111111111111111111111111111111111111111111111111111111100
|
|
res=1111111111111111111111111111111111111111111111111111111111111111
|
|
NOTE: same result as above; can not shift beyond -1
|
|
|
|
|
|
--- BIT SHIFT LEFT ON POSITIVE INTEGERS ---
|
|
Expression: 8 = 4 << 1
|
|
Decimal:
|
|
val=4
|
|
res=8
|
|
Binary:
|
|
val=0000000000000000000000000000000000000000000000000000000000000100
|
|
res=0000000000000000000000000000000000000000000000000000000000001000
|
|
NOTE: zeros fill in right side
|
|
|
|
Expression: 4611686018427387904 = 4 << 60
|
|
Decimal:
|
|
val=4
|
|
res=4611686018427387904
|
|
Binary:
|
|
val=0000000000000000000000000000000000000000000000000000000000000100
|
|
res=0100000000000000000000000000000000000000000000000000000000000000
|
|
|
|
Expression: -9223372036854775808 = 4 << 61
|
|
Decimal:
|
|
val=4
|
|
res=-9223372036854775808
|
|
Binary:
|
|
val=0000000000000000000000000000000000000000000000000000000000000100
|
|
res=1000000000000000000000000000000000000000000000000000000000000000
|
|
NOTE: sign bits get shifted out
|
|
|
|
Expression: 0 = 4 << 62
|
|
Decimal:
|
|
val=4
|
|
res=0
|
|
Binary:
|
|
val=0000000000000000000000000000000000000000000000000000000000000100
|
|
res=0000000000000000000000000000000000000000000000000000000000000000
|
|
NOTE: bits shift out left side
|
|
|
|
|
|
--- BIT SHIFT LEFT ON NEGATIVE INTEGERS ---
|
|
Expression: -8 = -4 << 1
|
|
Decimal:
|
|
val=-4
|
|
res=-8
|
|
Binary:
|
|
val=1111111111111111111111111111111111111111111111111111111111111100
|
|
res=1111111111111111111111111111111111111111111111111111111111111000
|
|
NOTE: zeros fill in right side
|
|
|
|
Expression: -9223372036854775808 = -4 << 61
|
|
Decimal:
|
|
val=-4
|
|
res=-9223372036854775808
|
|
Binary:
|
|
val=1111111111111111111111111111111111111111111111111111111111111100
|
|
res=1000000000000000000000000000000000000000000000000000000000000000
|
|
|
|
Expression: 0 = -4 << 62
|
|
Decimal:
|
|
val=-4
|
|
res=0
|
|
Binary:
|
|
val=1111111111111111111111111111111111111111111111111111111111111100
|
|
res=0000000000000000000000000000000000000000000000000000000000000000
|
|
NOTE: bits shift out left side, including sign bit
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
</para>
|
|
<warning>
|
|
<para>
|
|
Use functions from the <link linkend="book.gmp">gmp</link> extension for
|
|
bitwise manipulation on numbers beyond <literal>PHP_INT_MAX</literal>.
|
|
</para>
|
|
</warning>
|
|
|
|
<sect2 role="seealso">
|
|
&reftitle.seealso;
|
|
<para>
|
|
<simplelist>
|
|
<!-- <link linkend="language.oop5.basic.class.class">::class</link> -->
|
|
<member><function>pack</function></member>
|
|
<member><function>unpack</function></member>
|
|
<member><function>gmp_and</function></member>
|
|
<member><function>gmp_or</function></member>
|
|
<member><function>gmp_xor</function></member>
|
|
<member><function>gmp_testbit</function></member>
|
|
<member><function>gmp_clrbit</function></member>
|
|
</simplelist>
|
|
</para>
|
|
</sect2>
|
|
</sect1>
|
|
|
|
<sect1 xml:id="language.operators.comparison">
|
|
<title>Comparison Operators</title>
|
|
<simpara>
|
|
Comparison operators, as their name implies, allow you to compare
|
|
two values. You may also be interested in viewing
|
|
<link linkend="types.comparisons">the type comparison tables</link>,
|
|
as they show examples of various type related comparisons.
|
|
</simpara>
|
|
<table>
|
|
<title>Comparison Operators</title>
|
|
<tgroup cols="3">
|
|
<thead>
|
|
<row>
|
|
<entry>Example</entry>
|
|
<entry>Name</entry>
|
|
<entry>Result</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry>$a == $b</entry>
|
|
<entry>Equal</entry>
|
|
<entry>&true; if <varname>$a</varname> is equal to <varname>$b</varname> after type juggling.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a === $b</entry>
|
|
<entry>Identical</entry>
|
|
<entry>
|
|
&true; if <varname>$a</varname> is equal to <varname>$b</varname>, and they are of the same
|
|
type.
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a != $b</entry>
|
|
<entry>Not equal</entry>
|
|
<entry>&true; if <varname>$a</varname> is not equal to <varname>$b</varname> after type juggling.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a <> $b</entry>
|
|
<entry>Not equal</entry>
|
|
<entry>&true; if <varname>$a</varname> is not equal to <varname>$b</varname> after type juggling.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a !== $b</entry>
|
|
<entry>Not identical</entry>
|
|
<entry>
|
|
&true; if <varname>$a</varname> is not equal to <varname>$b</varname>, or they are not of the same
|
|
type.
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a < $b</entry>
|
|
<entry>Less than</entry>
|
|
<entry>&true; if <varname>$a</varname> is strictly less than <varname>$b</varname>.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a > $b</entry>
|
|
<entry>Greater than</entry>
|
|
<entry>&true; if <varname>$a</varname> is strictly greater than <varname>$b</varname>.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a <= $b</entry>
|
|
<entry>Less than or equal to </entry>
|
|
<entry>&true; if <varname>$a</varname> is less than or equal to <varname>$b</varname>.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a >= $b</entry>
|
|
<entry>Greater than or equal to </entry>
|
|
<entry>&true; if <varname>$a</varname> is greater than or equal to <varname>$b</varname>.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a <=> $b</entry>
|
|
<entry>Spaceship</entry>
|
|
<entry>
|
|
An <type>int</type> less than, equal to, or greater than zero when
|
|
<varname>$a</varname> is less than, equal to, or greater than
|
|
<varname>$b</varname>, respectively.
|
|
</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
<para>
|
|
If both operands are
|
|
<link linkend="language.types.numeric-strings">numeric strings</link>,
|
|
or one operand is a number and the other one is a
|
|
<link linkend="language.types.numeric-strings">numeric string</link>,
|
|
then the comparison is done numerically.
|
|
These rules also apply to the
|
|
<link linkend="control-structures.switch">switch</link> statement.
|
|
The type conversion does not take place when the comparison is
|
|
<literal>===</literal> or <literal>!==</literal> as this involves
|
|
comparing the type as well as the value.
|
|
</para>
|
|
|
|
<warning>
|
|
<para>
|
|
Prior to PHP 8.0.0, if a <type>string</type> is compared to a number
|
|
or a numeric string then the <type>string</type> was converted to a
|
|
number before performing the comparison. This can lead to surprising
|
|
results as can be seen with the following example:
|
|
<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
|
|
// Integers
|
|
echo 1 <=> 1; // 0
|
|
echo 1 <=> 2; // -1
|
|
echo 2 <=> 1; // 1
|
|
|
|
// Floats
|
|
echo 1.5 <=> 1.5; // 0
|
|
echo 1.5 <=> 2.5; // -1
|
|
echo 2.5 <=> 1.5; // 1
|
|
|
|
// Strings
|
|
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
|
|
|
|
// Objects
|
|
$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
|
|
|
|
// not only values are compared; keys must match
|
|
$a = (object) ["a" => "b"];
|
|
$b = (object) ["b" => "b"];
|
|
echo $a <=> $b; // 1
|
|
|
|
?>
|
|
]]>
|
|
|
|
</programlisting>
|
|
</informalexample>
|
|
</para>
|
|
|
|
<para>
|
|
For various types, comparison is done according to the following
|
|
table (in order).
|
|
</para>
|
|
<table xml:id="language.operators.comparison.types">
|
|
<title>Comparison with Various Types</title>
|
|
<tgroup cols="3">
|
|
<thead>
|
|
<row>
|
|
<entry>Type of Operand 1</entry>
|
|
<entry>Type of Operand 2</entry>
|
|
<entry>Result</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry><type>null</type> or <type>string</type></entry>
|
|
<entry><type>string</type></entry>
|
|
<entry>Convert &null; to "", numerical or lexical comparison</entry>
|
|
</row>
|
|
<row>
|
|
<entry><type>bool</type> or <type>null</type></entry>
|
|
<entry>anything</entry>
|
|
<entry>Convert both sides to <type>bool</type>, &false; < &true;</entry>
|
|
</row>
|
|
<row>
|
|
<entry><type>object</type></entry>
|
|
<entry><type>object</type></entry>
|
|
<entry>Built-in classes can define its own comparison, different classes
|
|
are uncomparable, same class see <link
|
|
linkend="language.oop5.object-comparison">Object Comparison</link>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry><type>string</type>, <type>resource</type>, <type>int</type> or <type>float</type></entry>
|
|
<entry><type>string</type>, <type>resource</type>, <type>int</type> or <type>float</type></entry>
|
|
<entry>Translate strings and resources to numbers, usual math</entry>
|
|
</row>
|
|
<row>
|
|
<entry><type>array</type></entry>
|
|
<entry><type>array</type></entry>
|
|
<entry>Array with fewer members is smaller, if key from operand 1 is not
|
|
found in operand 2 then arrays are uncomparable, otherwise - compare
|
|
value by value (see following example)</entry>
|
|
</row>
|
|
<row>
|
|
<entry><type>object</type></entry>
|
|
<entry>anything</entry>
|
|
<entry><type>object</type> is always greater</entry>
|
|
</row>
|
|
<row>
|
|
<entry><type>array</type></entry>
|
|
<entry>anything</entry>
|
|
<entry><type>array</type> is always greater</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
|
|
<para>
|
|
<example>
|
|
<title>Boolean/null comparison</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>Transcription of standard array comparison</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
// Arrays are compared like this with standard comparison operators
|
|
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 null; // uncomparable
|
|
} elseif ($val < $op2[$key]) {
|
|
return -1;
|
|
} elseif ($val > $op2[$key]) {
|
|
return 1;
|
|
}
|
|
}
|
|
return 0; // $op1 == $op2
|
|
}
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
</para>
|
|
|
|
<warning>
|
|
<title>Comparison of floating point numbers</title>
|
|
|
|
<para>
|
|
Because of the way <type>float</type>s are represented internally, you
|
|
should not test two <type>float</type>s for equality.
|
|
</para>
|
|
|
|
<para>
|
|
See the documentation for <type>float</type> for more information.
|
|
</para>
|
|
</warning>
|
|
|
|
<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>Ternary Operator</title>
|
|
<para>
|
|
Another conditional operator is the "?:" (or ternary) operator.
|
|
<example>
|
|
<title>Assigning a default value</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
// Example usage for: Ternary Operator
|
|
$action = (empty($_POST['action'])) ? 'default' : $_POST['action'];
|
|
|
|
// The above is identical to this if/else statement
|
|
if (empty($_POST['action'])) {
|
|
$action = 'default';
|
|
} else {
|
|
$action = $_POST['action'];
|
|
}
|
|
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
The expression <literal>(expr1) ? (expr2) : (expr3)</literal>
|
|
evaluates to <replaceable>expr2</replaceable> if
|
|
<replaceable>expr1</replaceable> evaluates to &true;, and
|
|
<replaceable>expr3</replaceable> if
|
|
<replaceable>expr1</replaceable> evaluates to &false;.
|
|
</para>
|
|
<para>
|
|
It is possible to leave out the middle part of the ternary operator.
|
|
Expression <literal>expr1 ?: expr3</literal> returns
|
|
<replaceable>expr1</replaceable> if <replaceable>expr1</replaceable>
|
|
evaluates to &true;, and <replaceable>expr3</replaceable> otherwise.
|
|
</para>
|
|
<note>
|
|
<simpara>
|
|
Please note that the ternary operator is an expression, and that it
|
|
doesn't evaluate to a variable, but to the result of an expression. This
|
|
is important to know if you want to return a variable by reference.
|
|
The statement <literal>return $var == 42 ? $a : $b;</literal> in a
|
|
return-by-reference function will therefore not work and a warning is
|
|
issued.
|
|
</simpara>
|
|
</note>
|
|
<note>
|
|
<para>
|
|
It is recommended to avoid "stacking" ternary expressions.
|
|
PHP's behaviour when using more than one unparenthesized ternary operator within a single
|
|
expression is non-obvious compared to other languages.
|
|
Indeed prior to PHP 8.0.0, ternary expressions were evaluated left-associative,
|
|
instead of right-associative like most other programming languages.
|
|
Relying on left-associativity is deprecated as of PHP 7.4.0.
|
|
As of PHP 8.0.0, the ternary operator is non-associative.
|
|
<example>
|
|
<title>Non-obvious Ternary Behaviour</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
// on first glance, the following appears to output 'true'
|
|
echo (true ? 'true' : false ? 't' : 'f');
|
|
|
|
// however, the actual output of the above is 't' prior to PHP 8.0.0
|
|
// this is because ternary expressions are left-associative
|
|
|
|
// the following is a more obvious version of the same code as above
|
|
echo ((true ? 'true' : false) ? 't' : 'f');
|
|
|
|
// here, one can see that the first expression is evaluated to 'true', which
|
|
// in turn evaluates to (bool)true, thus returning the true branch of the
|
|
// second ternary expression.
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
</para>
|
|
</note>
|
|
</sect2>
|
|
|
|
<sect2 xml:id="language.operators.comparison.coalesce">
|
|
<title>Null Coalescing Operator</title>
|
|
<para>
|
|
Further exists the "??" (or null coalescing) operator.
|
|
<example>
|
|
<title>Assigning a default value</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
// Example usage for: Null Coalesce Operator
|
|
$action = $_POST['action'] ?? 'default';
|
|
|
|
// The above is identical to this if/else statement
|
|
if (isset($_POST['action'])) {
|
|
$action = $_POST['action'];
|
|
} else {
|
|
$action = 'default';
|
|
}
|
|
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
The expression <literal>(expr1) ?? (expr2)</literal> evaluates to
|
|
<replaceable>expr2</replaceable> if <replaceable>expr1</replaceable> is
|
|
&null;, and <replaceable>expr1</replaceable> otherwise.
|
|
</para>
|
|
<para>
|
|
In particular, this operator does not emit a notice or warning if the left-hand side
|
|
value does not exist, just like <function>isset</function>. This is especially
|
|
useful on array keys.
|
|
</para>
|
|
<note>
|
|
<simpara>
|
|
Please note that the null coalescing operator is an expression, and that it
|
|
doesn't evaluate to a variable, but to the result of an expression. This
|
|
is important to know if you want to return a variable by reference.
|
|
The statement <literal>return $foo ?? $bar;</literal> in a
|
|
return-by-reference function will therefore not work and a warning is
|
|
issued.
|
|
</simpara>
|
|
</note>
|
|
<note>
|
|
<para>
|
|
Please note that the null coalescing operator allows for simple nesting:
|
|
<example>
|
|
<title>Nesting null coalescing operator</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
|
|
$foo = null;
|
|
$bar = null;
|
|
$baz = 1;
|
|
$qux = 2;
|
|
|
|
echo $foo ?? $bar ?? $baz ?? $qux; // outputs 1
|
|
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
</para>
|
|
</note>
|
|
</sect2>
|
|
</sect1>
|
|
|
|
<sect1 xml:id="language.operators.errorcontrol">
|
|
<title>Error Control Operators</title>
|
|
<simpara>
|
|
PHP supports one error control operator: the at sign (<literal>@</literal>).
|
|
When prepended to an expression in PHP, any diagnostic error that might
|
|
be generated by that expression will be suppressed.
|
|
</simpara>
|
|
<para>
|
|
If a custom error handler function is set with
|
|
<function>set_error_handler</function>, it will still be called even though
|
|
the diagnostic has been suppressed, as such the custom error handler should
|
|
call <function>error_reporting</function> and verify that the
|
|
<literal>@</literal> operator was used in the following way:
|
|
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
function my_error_handler($err_no, $err_msg, $filename, $linenum) {
|
|
if (!(error_reporting() & $err_no)) {
|
|
return false; // Silenced
|
|
}
|
|
// ...
|
|
}
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
</para>
|
|
|
|
<warning>
|
|
<para>
|
|
Prior to PHP 8.0.0, the value of the severity passed to the custom error
|
|
handler was always <literal>0</literal> if the diagnostic was suppressed.
|
|
This is no longer the case as of PHP 8.0.0.
|
|
</para>
|
|
</warning>
|
|
|
|
<simpara>
|
|
Any error message generated by the expression is available in the <literal>"message"</literal>
|
|
element of the array returned by <function>error_get_last</function>.
|
|
The result of that function will change on each error, so it needs to be checked early.
|
|
</simpara>
|
|
<para>
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
/* Intentional file error */
|
|
$my_file = @file ('non_existent_file') or
|
|
die ("Failed opening file: error was '" . error_get_last()['message'] . "'");
|
|
|
|
// this works for any expression, not just functions:
|
|
$value = @$cache[$key];
|
|
// will not issue a notice if the index $key doesn't exist.
|
|
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
</para>
|
|
<note>
|
|
<simpara>
|
|
The <literal>@</literal>-operator works only on
|
|
<link linkend="language.expressions">expressions</link>.
|
|
A simple rule of thumb is: if one can take the value of something,
|
|
then one can prepend the <literal>@</literal> operator to it.
|
|
For instance, it can be prepended to variables, functions calls,
|
|
certain language construct calls (e.g. <function>include</function>),
|
|
and so forth.
|
|
It cannot be prepended to function or class definitions,
|
|
or conditional structures such as <literal>if</literal> and
|
|
&foreach;, and so forth.
|
|
</simpara>
|
|
</note>
|
|
<warning>
|
|
<para>
|
|
Prior to PHP 8.0.0, it was possible for the <literal>@</literal> operator
|
|
to disable critical errors that will terminate script execution.
|
|
For example, prepending <literal>@</literal> to a call of a function
|
|
which did not exist, by being unavailable or mistyped, would cause
|
|
the script to terminate with no indication as to why.
|
|
</para>
|
|
</warning>
|
|
|
|
<sect2 role="seealso">
|
|
&reftitle.seealso;
|
|
<para>
|
|
<simplelist>
|
|
<member><function>error_reporting</function></member>
|
|
<member><link linkend="ref.errorfunc">Error Handling and Logging functions</link></member>
|
|
</simplelist>
|
|
</para>
|
|
</sect2>
|
|
</sect1>
|
|
|
|
<sect1 xml:id="language.operators.execution">
|
|
<title>Execution Operators</title>
|
|
<para>
|
|
PHP supports one execution operator: backticks (``). Note that
|
|
these are not single-quotes! PHP will attempt to execute the
|
|
contents of the backticks as a shell command; the output will be
|
|
returned (i.e., it won't simply be dumped to output; it can be
|
|
assigned to a variable). Use of the backtick operator is identical
|
|
to <function>shell_exec</function>.
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
$output = `ls -al`;
|
|
echo "<pre>$output</pre>";
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
</para>
|
|
<note>
|
|
<para>
|
|
The backtick operator is disabled when
|
|
<function>shell_exec</function> is disabled.
|
|
</para>
|
|
</note>
|
|
<note>
|
|
<para>
|
|
Unlike some other languages, backticks have no special meaning
|
|
within double-quoted strings.
|
|
</para>
|
|
</note>
|
|
|
|
<sect2 role="seealso">
|
|
&reftitle.seealso;
|
|
<para>
|
|
<simplelist>
|
|
<member><link linkend="ref.exec">Program Execution functions</link></member>
|
|
<member><function>popen</function></member>
|
|
<member><function>proc_open</function></member>
|
|
<member><link linkend="features.commandline">Using PHP from the commandline</link></member>
|
|
</simplelist>
|
|
</para>
|
|
</sect2>
|
|
</sect1>
|
|
|
|
<sect1 xml:id="language.operators.increment">
|
|
<title>Incrementing/Decrementing Operators</title>
|
|
<para>
|
|
PHP supports C-style pre- and post-increment and decrement
|
|
operators.
|
|
</para>
|
|
<note>
|
|
<simpara>
|
|
The increment/decrement operators only affect numbers and strings.
|
|
Arrays, objects, booleans and resources are not affected.
|
|
Decrementing &null; values has no effect too, but incrementing them
|
|
results in <literal>1</literal>.
|
|
</simpara>
|
|
</note>
|
|
<table>
|
|
<title>Increment/decrement Operators</title>
|
|
<tgroup cols="3">
|
|
<thead>
|
|
<row>
|
|
<entry>Example</entry>
|
|
<entry>Name</entry>
|
|
<entry>Effect</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry>++$a</entry>
|
|
<entry>Pre-increment</entry>
|
|
<entry>Increments <varname>$a</varname> by one, then returns <varname>$a</varname>.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a++</entry>
|
|
<entry>Post-increment</entry>
|
|
<entry>Returns <varname>$a</varname>, then increments <varname>$a</varname> by one.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>--$a</entry>
|
|
<entry>Pre-decrement</entry>
|
|
<entry>Decrements <varname>$a</varname> by one, then returns <varname>$a</varname>.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a--</entry>
|
|
<entry>Post-decrement</entry>
|
|
<entry>Returns <varname>$a</varname>, then decrements <varname>$a</varname> by one.</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
<para>
|
|
Here's a simple example script:
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
echo "<h3>Postincrement</h3>";
|
|
$a = 5;
|
|
echo "Should be 5: " . $a++ . "<br />\n";
|
|
echo "Should be 6: " . $a . "<br />\n";
|
|
|
|
echo "<h3>Preincrement</h3>";
|
|
$a = 5;
|
|
echo "Should be 6: " . ++$a . "<br />\n";
|
|
echo "Should be 6: " . $a . "<br />\n";
|
|
|
|
echo "<h3>Postdecrement</h3>";
|
|
$a = 5;
|
|
echo "Should be 5: " . $a-- . "<br />\n";
|
|
echo "Should be 4: " . $a . "<br />\n";
|
|
|
|
echo "<h3>Predecrement</h3>";
|
|
$a = 5;
|
|
echo "Should be 4: " . --$a . "<br />\n";
|
|
echo "Should be 4: " . $a . "<br />\n";
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
</para>
|
|
<para>
|
|
PHP follows Perl's convention when dealing with arithmetic operations
|
|
on character variables and not C's. For example, in PHP and Perl
|
|
<literal>$a = 'Z'; $a++;</literal> turns <literal>$a</literal> into <literal>'AA'</literal>, while in C
|
|
<literal>a = 'Z'; a++;</literal> turns <literal>a</literal> into <literal>'['</literal>
|
|
(ASCII value of <literal>'Z'</literal> is 90, ASCII value of <literal>'['</literal> is 91).
|
|
Note that character variables can be incremented but not decremented and
|
|
even so only plain ASCII alphabets and digits (a-z, A-Z and 0-9) are supported.
|
|
Incrementing/decrementing other character variables has no effect, the
|
|
original string is unchanged.
|
|
<example>
|
|
<title>Arithmetic Operations on Character Variables</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
echo '== Alphabets ==' . PHP_EOL;
|
|
$s = 'W';
|
|
for ($n=0; $n<6; $n++) {
|
|
echo ++$s . PHP_EOL;
|
|
}
|
|
// Digit characters behave differently
|
|
echo '== Digits ==' . PHP_EOL;
|
|
$d = 'A8';
|
|
for ($n=0; $n<6; $n++) {
|
|
echo ++$d . PHP_EOL;
|
|
}
|
|
$d = 'A08';
|
|
for ($n=0; $n<6; $n++) {
|
|
echo ++$d . PHP_EOL;
|
|
}
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
== Characters ==
|
|
X
|
|
Y
|
|
Z
|
|
AA
|
|
AB
|
|
AC
|
|
== Digits ==
|
|
A9
|
|
B0
|
|
B1
|
|
B2
|
|
B3
|
|
B4
|
|
A09
|
|
A10
|
|
A11
|
|
A12
|
|
A13
|
|
A14
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
</para>
|
|
<para>
|
|
Incrementing or decrementing booleans has no effect.
|
|
</para>
|
|
</sect1>
|
|
|
|
<sect1 xml:id="language.operators.logical">
|
|
<title>Logical Operators</title>
|
|
|
|
<table>
|
|
<title>Logical Operators</title>
|
|
<tgroup cols="3">
|
|
<thead>
|
|
<row>
|
|
<entry>Example</entry>
|
|
<entry>Name</entry>
|
|
<entry>Result</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry>$a and $b</entry>
|
|
<entry>And</entry>
|
|
<entry>&true; if both <varname>$a</varname> and <varname>$b</varname> are &true;.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a or $b</entry>
|
|
<entry>Or</entry>
|
|
<entry>&true; if either <varname>$a</varname> or <varname>$b</varname> is &true;.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a xor $b</entry>
|
|
<entry>Xor</entry>
|
|
<entry>&true; if either <varname>$a</varname> or <varname>$b</varname> is &true;, but not both.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>! $a</entry>
|
|
<entry>Not</entry>
|
|
<entry>&true; if <varname>$a</varname> is not &true;.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a && $b</entry>
|
|
<entry>And</entry>
|
|
<entry>&true; if both <varname>$a</varname> and <varname>$b</varname> are &true;.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a || $b</entry>
|
|
<entry>Or</entry>
|
|
<entry>&true; if either <varname>$a</varname> or <varname>$b</varname> is &true;.</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
<simpara>
|
|
The reason for the two different variations of "and" and "or"
|
|
operators is that they operate at different precedences. (See
|
|
<link linkend="language.operators.precedence">Operator
|
|
Precedence</link>.)
|
|
</simpara>
|
|
<example>
|
|
<title>Logical operators illustrated</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
|
|
// --------------------
|
|
// foo() will never get called as those operators are short-circuit
|
|
|
|
$a = (false && foo());
|
|
$b = (true || foo());
|
|
$c = (false and foo());
|
|
$d = (true or foo());
|
|
|
|
// --------------------
|
|
// "||" has a greater precedence than "or"
|
|
|
|
// The result of the expression (false || true) is assigned to $e
|
|
// Acts like: ($e = (false || true))
|
|
$e = false || true;
|
|
|
|
// The constant false is assigned to $f before the "or" operation occurs
|
|
// Acts like: (($f = false) or true)
|
|
$f = false or true;
|
|
|
|
var_dump($e, $f);
|
|
|
|
// --------------------
|
|
// "&&" has a greater precedence than "and"
|
|
|
|
// The result of the expression (true && false) is assigned to $g
|
|
// Acts like: ($g = (true && false))
|
|
$g = true && false;
|
|
|
|
// The constant true is assigned to $h before the "and" operation occurs
|
|
// Acts like: (($h = true) and false)
|
|
$h = true and false;
|
|
|
|
var_dump($g, $h);
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs.similar;
|
|
<screen>
|
|
<![CDATA[
|
|
bool(true)
|
|
bool(false)
|
|
bool(false)
|
|
bool(true)
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
</sect1>
|
|
|
|
<sect1 xml:id="language.operators.string">
|
|
<title>String Operators</title>
|
|
<simpara>
|
|
There are two <type>string</type> operators. The first is the
|
|
concatenation operator ('.'), which returns the concatenation of its
|
|
right and left arguments. The second is the concatenating assignment
|
|
operator ('<literal>.=</literal>'), which appends the argument on the right side to
|
|
the argument on the left side. Please read <link
|
|
linkend="language.operators.assignment">Assignment
|
|
Operators</link> for more information.
|
|
</simpara>
|
|
|
|
<para>
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
$a = "Hello ";
|
|
$b = $a . "World!"; // now $b contains "Hello World!"
|
|
|
|
$a = "Hello ";
|
|
$a .= "World!"; // now $a contains "Hello World!"
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
</para>
|
|
|
|
<sect2 role="seealso">
|
|
&reftitle.seealso;
|
|
<para>
|
|
<simplelist>
|
|
<member><link linkend="language.types.string">String type</link></member>
|
|
<member><link linkend="ref.strings">String functions</link></member>
|
|
</simplelist>
|
|
</para>
|
|
</sect2>
|
|
</sect1>
|
|
|
|
<sect1 xml:id="language.operators.array">
|
|
<title>Array Operators</title>
|
|
<table>
|
|
<title>Array Operators</title>
|
|
<tgroup cols="3">
|
|
<thead>
|
|
<row>
|
|
<entry>Example</entry>
|
|
<entry>Name</entry>
|
|
<entry>Result</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry>$a + $b</entry>
|
|
<entry>Union</entry>
|
|
<entry>Union of <varname>$a</varname> and <varname>$b</varname>.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a == $b</entry>
|
|
<entry>Equality</entry>
|
|
<entry>&true; if <varname>$a</varname> and <varname>$b</varname> have the same key/value pairs.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a === $b</entry>
|
|
<entry>Identity</entry>
|
|
<entry>&true; if <varname>$a</varname> and <varname>$b</varname> have the same key/value pairs in the same
|
|
order and of the same types.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a != $b</entry>
|
|
<entry>Inequality</entry>
|
|
<entry>&true; if <varname>$a</varname> is not equal to <varname>$b</varname>.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a <> $b</entry>
|
|
<entry>Inequality</entry>
|
|
<entry>&true; if <varname>$a</varname> is not equal to <varname>$b</varname>.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>$a !== $b</entry>
|
|
<entry>Non-identity</entry>
|
|
<entry>&true; if <varname>$a</varname> is not identical to <varname>$b</varname>.</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
<para>
|
|
The <literal>+</literal> operator returns the right-hand array appended
|
|
to the left-hand array; for keys that exist in both arrays, the elements
|
|
from the left-hand array will be used, and the matching elements from the
|
|
right-hand array will be ignored.
|
|
</para>
|
|
<para>
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
$a = array("a" => "apple", "b" => "banana");
|
|
$b = array("a" => "pear", "b" => "strawberry", "c" => "cherry");
|
|
|
|
$c = $a + $b; // Union of $a and $b
|
|
echo "Union of \$a and \$b: \n";
|
|
var_dump($c);
|
|
|
|
$c = $b + $a; // Union of $b and $a
|
|
echo "Union of \$b and \$a: \n";
|
|
var_dump($c);
|
|
|
|
$a += $b; // Union of $a += $b is $a and $b
|
|
echo "Union of \$a += \$b: \n";
|
|
var_dump($a);
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
When executed, this script will print the following:
|
|
<screen role="php">
|
|
<![CDATA[
|
|
Union of $a and $b:
|
|
array(3) {
|
|
["a"]=>
|
|
string(5) "apple"
|
|
["b"]=>
|
|
string(6) "banana"
|
|
["c"]=>
|
|
string(6) "cherry"
|
|
}
|
|
Union of $b and $a:
|
|
array(3) {
|
|
["a"]=>
|
|
string(4) "pear"
|
|
["b"]=>
|
|
string(10) "strawberry"
|
|
["c"]=>
|
|
string(6) "cherry"
|
|
}
|
|
Union of $a += $b:
|
|
array(3) {
|
|
["a"]=>
|
|
string(5) "apple"
|
|
["b"]=>
|
|
string(6) "banana"
|
|
["c"]=>
|
|
string(6) "cherry"
|
|
}
|
|
]]>
|
|
</screen>
|
|
</para>
|
|
<para>
|
|
Elements of arrays are equal for the comparison if they have the
|
|
same key and value.
|
|
</para>
|
|
<para>
|
|
<example>
|
|
<title>Comparing arrays</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
$a = array("apple", "banana");
|
|
$b = array(1 => "banana", "0" => "apple");
|
|
|
|
var_dump($a == $b); // bool(true)
|
|
var_dump($a === $b); // bool(false)
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
</para>
|
|
|
|
<sect2 role="seealso">
|
|
&reftitle.seealso;
|
|
<para>
|
|
<simplelist>
|
|
<member><link linkend="language.types.array">Array type</link></member>
|
|
<member><link linkend="ref.array">Array functions</link></member>
|
|
</simplelist>
|
|
</para>
|
|
</sect2>
|
|
</sect1>
|
|
|
|
<sect1 xml:id="language.operators.type">
|
|
<title>Type Operators</title>
|
|
<para>
|
|
<literal>instanceof</literal> is used to determine whether a PHP variable
|
|
is an instantiated object of a certain
|
|
<link linkend="language.oop5.basic.class">class</link>:
|
|
<example>
|
|
<title>Using <literal>instanceof</literal> with classes</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
class MyClass
|
|
{
|
|
}
|
|
|
|
class NotMyClass
|
|
{
|
|
}
|
|
$a = new MyClass;
|
|
|
|
var_dump($a instanceof MyClass);
|
|
var_dump($a instanceof NotMyClass);
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
bool(true)
|
|
bool(false)
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
</para>
|
|
<para>
|
|
<literal>instanceof</literal> can also be used to determine whether a variable
|
|
is an instantiated object of a class that inherits from a parent class:
|
|
<example>
|
|
<title>Using <literal>instanceof</literal> with inherited classes</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
class ParentClass
|
|
{
|
|
}
|
|
|
|
class MyClass extends ParentClass
|
|
{
|
|
}
|
|
|
|
$a = new MyClass;
|
|
|
|
var_dump($a instanceof MyClass);
|
|
var_dump($a instanceof ParentClass);
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
bool(true)
|
|
bool(true)
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
</para>
|
|
<para>
|
|
To check if an object is <emphasis>not</emphasis> an instanceof a class, the
|
|
<link linkend="language.operators.logical">logical <literal>not</literal>
|
|
operator</link> can be used.
|
|
<example>
|
|
<title>Using <literal>instanceof</literal> to check if object is <emphasis>not</emphasis> an
|
|
instanceof a class</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
class MyClass
|
|
{
|
|
}
|
|
|
|
$a = new MyClass;
|
|
var_dump(!($a instanceof stdClass));
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
bool(true)
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
</para>
|
|
<para>
|
|
Lastly, <literal>instanceof</literal> can also be used to determine whether
|
|
a variable is an instantiated object of a class that implements an
|
|
<link linkend="language.oop5.interfaces">interface</link>:
|
|
<example>
|
|
<title>Using <literal>instanceof</literal> with interfaces</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
interface MyInterface
|
|
{
|
|
}
|
|
|
|
class MyClass implements MyInterface
|
|
{
|
|
}
|
|
|
|
$a = new MyClass;
|
|
|
|
var_dump($a instanceof MyClass);
|
|
var_dump($a instanceof MyInterface);
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
bool(true)
|
|
bool(true)
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
</para>
|
|
<para>
|
|
Although <literal>instanceof</literal> is usually used with a literal classname,
|
|
it can also be used with another object or a string variable:
|
|
<example>
|
|
<title>Using <literal>instanceof</literal> with other variables</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
interface MyInterface
|
|
{
|
|
}
|
|
|
|
class MyClass implements MyInterface
|
|
{
|
|
}
|
|
|
|
$a = new MyClass;
|
|
$b = new MyClass;
|
|
$c = 'MyClass';
|
|
$d = 'NotMyClass';
|
|
|
|
var_dump($a instanceof $b); // $b is an object of class MyClass
|
|
var_dump($a instanceof $c); // $c is a string 'MyClass'
|
|
var_dump($a instanceof $d); // $d is a string 'NotMyClass'
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
bool(true)
|
|
bool(true)
|
|
bool(false)
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
</para>
|
|
<para>
|
|
instanceof does not throw any error if the variable being tested is not
|
|
an object, it simply returns &false;. Constants, however, were not allowed
|
|
prior to PHP 7.3.0.
|
|
<example>
|
|
<title>Using <literal>instanceof</literal> to test other variables</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
$a = 1;
|
|
$b = NULL;
|
|
$c = imagecreate(5, 5);
|
|
var_dump($a instanceof stdClass); // $a is an integer
|
|
var_dump($b instanceof stdClass); // $b is NULL
|
|
var_dump($c instanceof stdClass); // $c is a resource
|
|
var_dump(FALSE instanceof stdClass);
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
bool(false)
|
|
bool(false)
|
|
bool(false)
|
|
PHP Fatal error: instanceof expects an object instance, constant given
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
</para>
|
|
<para>
|
|
As of PHP 7.3.0, constants are allowed on the left-hand-side of the
|
|
<literal>instanceof</literal> operator.
|
|
<example>
|
|
<title>Using <literal>instanceof</literal> to test constants</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
var_dump(FALSE instanceof stdClass);
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs.73;
|
|
<screen>
|
|
<![CDATA[
|
|
bool(false)
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
</para>
|
|
<para>
|
|
As of PHP 8.0.0, <literal>instanceof</literal> can now be used with arbitrary expressions.
|
|
The expression must be wrapped in parentheses and produce a <type>string</type>.
|
|
<!-- RFC: https://wiki.php.net/rfc/variable_syntax_tweaks -->
|
|
<example>
|
|
<title>Using <literal>instanceof</literal> with an arbitrary expression</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
|
|
class ClassA extends \stdClass {}
|
|
class ClassB extends \stdClass {}
|
|
class ClassC extends ClassB {}
|
|
class ClassD extends ClassA {}
|
|
|
|
function getSomeClass(): string
|
|
{
|
|
return ClassA::class;
|
|
}
|
|
|
|
var_dump(new ClassA instanceof ('std' . 'Class'));
|
|
var_dump(new ClassB instanceof ('Class' . 'B'));
|
|
var_dump(new ClassC instanceof ('Class' . 'A'));
|
|
var_dump(new ClassD instanceof (getSomeClass()));
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs.8;
|
|
<screen>
|
|
<![CDATA[
|
|
bool(true)
|
|
bool(true)
|
|
bool(false)
|
|
bool(true)
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
</para>
|
|
<simpara>
|
|
The <literal>instanceof</literal> operator has a functional variant
|
|
with the <function>is_a</function> function.
|
|
</simpara>
|
|
|
|
<sect2 role="seealso">
|
|
&reftitle.seealso;
|
|
<para>
|
|
<simplelist>
|
|
<member><function>get_class</function></member>
|
|
<member><function>is_a</function></member>
|
|
</simplelist>
|
|
</para>
|
|
</sect2>
|
|
</sect1>
|
|
</chapter>
|
|
|
|
<!-- Keep this comment at the end of the file
|
|
Local variables:
|
|
mode: sgml
|
|
sgml-omittag:t
|
|
sgml-shorttag:t
|
|
sgml-minimize-attributes:nil
|
|
sgml-always-quote-attributes:t
|
|
sgml-indent-step:1
|
|
sgml-indent-data:t
|
|
indent-tabs-mode:nil
|
|
sgml-parent-document:nil
|
|
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
|
|
sgml-exposed-tags:nil
|
|
sgml-local-catalogs:nil
|
|
sgml-local-ecat-files:nil
|
|
End:
|
|
vim600: syn=xml fen fdm=syntax fdl=2 si
|
|
vim: et tw=78 syn=sgml
|
|
vi: ts=1 sw=1
|
|
-->
|