1
0
mirror of https://github.com/php/doc-es.git synced 2026-03-26 00:12:06 +01:00
Files
archived-doc-es/language/operators.xml
Pedro Antonio Gil Rodríguez 73375a8f2e Actualización a la última versión
git-svn-id: https://svn.php.net/repository/phpdoc/es/trunk@338335 c90b9560-bf6c-de11-be94-00142212c4b1
2015-12-21 13:57:57 +00:00

2380 lines
69 KiB
XML

<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
<!-- EN-Revision: f99e5eb6c7081af49f2ecc1a7cbe7b7e39565d9e Maintainer: seros Status: ready -->
<!-- Reviewed: no Maintainer: andresdzphp -->
<chapter xml:id="language.operators" xmlns="http://docbook.org/ns/docbook">
<title>Operadores</title>
<simpara>
Un operador es algo que toma uno más valores (o
expresiones, en la jerga de programación) y produce otro valor (de modo que la
construcción en si misma se convierte en una expresión).
</simpara>
<para>
Los operadores se pueden agrupar de acuerdo con el número de valores que toman. Los operadores
unarios toman sólo un valor, por ejemplo <literal>!</literal> (el
<link linkend="language.operators.logical">operador lógico de negación</link>) o
<literal>++</literal> (el
<link linkend="language.operators.increment">operador de incremento</link>).
Los operadores binarios toman dos valores, como los familiares
<link linkend="language.operators.arithmetic">operadores aritméticos</link>
<literal>+</literal> (suma) y <literal>-</literal> (resta), y la
mayoría de los operadores de PHP entran en esta categoría. Finalmente, hay sólo
un <link linkend="language.operators.comparison.ternary">operador
ternario</link>, <literal>? :</literal>, el cual toma tres valores; usualmente a este se
le refiere simplemente como "el operador ternario" (aunque podría
tal vez llamarse más correctamente como el operador condicional).
</para>
<para>
Una lista completa de operadores de PHP sigue en la sección
<link linkend="language.operators.precedence">Precedencia de Operadores</link>.
La sección también explica la precedencia y asociatividad de los operadores, las cuales gobiernan
exactamente cómo son evaluadas expresiones que contienen varios diferentes
operadores.
</para>
<sect1 xml:id="language.operators.precedence">
<title>Precedencia de operadores</title>
<para>
La precedencia de un operador indica qué tan "estrechamente" se unen dos
expresiones juntas. Por ejemplo, en la expresión <literal>1 +
5 * 3 </literal>, la respuesta es <literal>16</literal> y no
<literal>18</literal> porque el operador de multiplicación ("*")
tiene una precedencia mayor que el operador de adición ("+").
Los paréntesis pueden ser usados para forzar la precedencia, si es necesario. Por
ejemplo: <literal>(1 + 5) * 3</literal> se evalúa como
<literal>18</literal>.
</para>
<para>
Cuando los operadores tienen igual precedencia su asociatividad decide
cómo se agrupan. Por ejemplo "-" tiene asociatividad a izquierda, así
<literal>1 - 2 - 3</literal> se agrupa como <literal>(1 - 2) - 3</literal>
y se evalúa a <literal>-4</literal>. "=", por otra parte, tiene
asociatividad a derecha, así <literal>$a = $b = $c</literal> se agrupa como
<literal>$a = ($b = $c)</literal>.
</para>
<para>
Los operadores de igual precedencia que no son asociativos no pueden usarse
unos junto a otros, por ejemplo, <literal>1 &lt; 2 &gt; 1</literal> es
ilegal en PHP. La expresión <literal>1 &lt;= 1 == 1</literal>, por otro
lado, es legal, ya que el operador <literal>==</literal> tiene menos
precedencia que el operador <literal>&lt;=</literal>.
</para>
<para>
El uso de paréntesis, incluso cuando no es estrictamente necesario, a menudo puede
aumentar la legibilidad del código haciendo grupos explícitamente en lugar de confiar
en la precedencia y asociatividad implícitas del operador.
</para>
<para>
La siguiente tabla enumera los operadores en orden de precedencia, con
los de más alta precedencia al inicio. Los operadores en la misma línea
tienen igual precedencia, en cuyo caso la asociatividad decide el agrupamiento.
<table>
<title>Precedencia de operadores</title>
<tgroup cols="2">
<thead>
<row>
<entry>Asociatividad</entry>
<entry>Operadores</entry>
<entry>Información adicional</entry>
</row>
</thead>
<tbody>
<row>
<entry>no asociativo</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>izquierda</entry>
<entry><literal>[</literal></entry>
<entry><function>array</function></entry>
</row>
<row>
<entry>derecha</entry>
<entry><literal>**</literal></entry>
<entry><link linkend="language.operators.arithmetic">aritmética</link></entry>
</row>
<row>
<entry>derecha</entry>
<entry>
<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.types">tipos</link> e <link linkend="language.operators.increment">incremento/decremento</link>
</entry>
</row>
<row>
<entry>no asociativo</entry>
<entry><literal>instanceof</literal></entry>
<entry>
<link linkend="language.types">tipos</link>
</entry>
</row>
<row>
<entry>derecha</entry>
<entry><literal>!</literal></entry>
<entry>
<link linkend="language.operators.logical">lógico</link>
</entry>
</row>
<row>
<entry>izquierda</entry>
<entry>
<literal>*</literal>
<literal>/</literal>
<literal>%</literal>
</entry>
<entry>
<link linkend="language.operators.arithmetic">aritmética</link>
</entry>
</row>
<row>
<entry>izquierda</entry>
<entry>
<literal>+</literal>
<literal>-</literal>
<literal>.</literal>
</entry>
<entry>
<link linkend="language.operators.arithmetic">aritmética</link>&listendand;
<link linkend="language.operators.string">string</link></entry>
</row>
<row>
<entry>izquierda</entry>
<entry>
<literal>&lt;&lt;</literal>
<literal>&gt;&gt;</literal>
</entry>
<entry>
<link linkend="language.operators.bitwise">bit a bit</link>
</entry>
</row>
<row>
<entry>no asociativo</entry>
<entry>
<literal>&lt;</literal>
<literal>&lt;=</literal>
<literal>&gt;</literal>
<literal>&gt;=</literal>
</entry>
<entry>
<link linkend="language.operators.comparison">comparación</link>
</entry>
</row>
<row>
<entry>no asociativo</entry>
<entry>
<literal>==</literal>
<literal>!=</literal>
<literal>===</literal>
<literal>!==</literal>
<literal>&lt;&gt;</literal>
<literal>&lt;=&gt;</literal>
</entry>
<entry>
<link linkend="language.operators.comparison">comparación</link>
</entry>
</row>
<row>
<entry>izquierda</entry>
<entry><literal>&amp;</literal></entry>
<entry>
<link linkend="language.operators.bitwise">bit a bit</link>&listendand;
<link linkend="language.references">referencias</link></entry>
</row>
<row>
<entry>izquierda</entry>
<entry><literal>^</literal></entry>
<entry>
<link linkend="language.operators.bitwise">bit a bit</link>
</entry>
</row>
<row>
<entry>izquierda</entry>
<entry><literal>|</literal></entry>
<entry>
<link linkend="language.operators.bitwise">bit a bit</link>
</entry>
</row>
<row>
<entry>izquierda</entry>
<entry><literal>&amp;&amp;</literal></entry>
<entry>
<link linkend="language.operators.logical">lógico</link>
</entry>
</row>
<row>
<entry>izquierda</entry>
<entry><literal>||</literal></entry>
<entry>
<link linkend="language.operators.logical">lógico</link>
</entry>
</row>
<row>
<entry>derecha</entry>
<entry><literal>??</literal></entry>
<entry>
<link linkend="language.operators.comparison">comparación</link>
</entry>
</row>
<row>
<entry>izquierda</entry>
<entry><literal>? :</literal></entry>
<entry>
<link linkend="language.operators.comparison.ternary">ternario</link>
</entry>
</row>
<row>
<entry>derecha</entry>
<entry>
<literal>=</literal>
<literal>+=</literal>
<literal>-=</literal>
<literal>*=</literal>
<literal>**=</literal>
<literal>/=</literal>
<literal>.=</literal>
<literal>%=</literal>
<literal>&amp;=</literal>
<literal>|=</literal>
<literal>^=</literal>
<literal>&lt;&lt;=</literal>
<literal>&gt;&gt;=</literal>
<literal>=&gt;</literal>
</entry>
<entry>
<link linkend="language.operators.assignment">asignación</link>
</entry>
</row>
<row>
<entry>izquierda</entry>
<entry><literal>and</literal></entry>
<entry>
<link linkend="language.operators.logical">lógico</link>
</entry>
</row>
<row>
<entry>izquierda</entry>
<entry><literal>xor</literal></entry>
<entry>
<link linkend="language.operators.logical">lógico</link>
</entry>
</row>
<row>
<entry>izquierda</entry>
<entry><literal>or</literal></entry>
<entry>
<link linkend="language.operators.logical">lógico</link>
</entry>
</row>
<row>
<entry>izquierda</entry>
<entry><literal>,</literal></entry>
<entry>muchos usos</entry>
</row>
</tbody>
</tgroup>
</table>
</para>
<para>
<example>
<title>Asociatividad</title>
<programlisting role="php">
<![CDATA[
<?php
$a = 3 * 3 % 5; // (3 * 3) % 5 = 4
// la asociatividad del operador ternario difiere de C/C++
$a = true ? 0 : true ? 1 : 2; // (true ? 0 : true) ? 1 : 2 = 2
$a = 1;
$b = 2;
$a = $b += 3; // $a = ($b += 3) -> $a = 5, $b = 5
?>
]]>
</programlisting>
</example>
</para>
<para>
La precedencia y asociatividad de los operadores solamente determinan cómo
se agrupan las expresiones, no especifican un orden de evaluación. PHP no
especifica (en general) el orden en que se evalúa una expresión
y se debería evitar el código que se asume un orden específico de evaluación,
ya que el comportamiento puede cambiar entre versiones de PHP o dependiendo de
código circundante.
<example>
<title>Orden de evaluación no definido</title>
<programlisting role="php">
<![CDATA[
<?php
$a = 1;
echo $a + $a++; // podría mostrar 2 o 3
$i = 1;
$array[$i] = $i++; // podría establecer el índice a 1 o 2
?>
]]>
</programlisting>
</example>
</para>
<note>
<para>
Aunque <literal>=</literal> tiene una precedencia menor que
la mayoría de los demás operadores, PHP aun permitirá expresiones
similares a lo siguiente: <literal>if (!$a = foo())</literal>,
en cuyo caso el valor devuelto de <literal>foo()</literal> es
puesto en <varname>$a</varname>.
</para>
</note>
</sect1>
<sect1 xml:id="language.operators.arithmetic">
<title>Operadores aritméticos</title>
<simpara>
¿Recuerda la aritmética básica de la escuela? Estos funcionan
igual que aquellos.
</simpara>
<table>
<title>Operadores aritméticos</title>
<tgroup cols="3">
<thead>
<row>
<entry>Ejemplo</entry>
<entry>Nombre</entry>
<entry>Resultado</entry>
</row>
</thead>
<tbody>
<row>
<entry>-$a</entry>
<entry>Negación</entry>
<entry>Opuesto de <varname>$a</varname>.</entry>
</row>
<row>
<entry>$a + $b</entry>
<entry>Adición</entry>
<entry>Suma de <varname>$a</varname> y <varname>$b</varname>.</entry>
</row>
<row>
<entry>$a - $b</entry>
<entry>Sustracción</entry>
<entry>Diferencia de <varname>$a</varname> y <varname>$b</varname>.</entry>
</row>
<row>
<entry>$a * $b</entry>
<entry>Multiplicación</entry>
<entry>Producto de <varname>$a</varname> y <varname>$b</varname>.</entry>
</row>
<row>
<entry>$a / $b</entry>
<entry>División</entry>
<entry>Cociente de <varname>$a</varname> y <varname>$b</varname>.</entry>
</row>
<row>
<entry>$a % $b</entry>
<entry>Módulo</entry>
<entry>Resto de <varname>$a</varname> dividido por <varname>$b</varname>.</entry>
</row>
<row>
<entry>$a ** $b</entry>
<entry>Exponenciación</entry>
<entry>Resultado de elevar <varname>$a</varname> a la potencia <varname>$b</varname>ésima. Introducido en PHP 5.6.</entry>
</row>
</tbody>
</tgroup>
</table>
<simpara>
El operador de división ("/") devuelve un valor flotante a menos que los dos operandos
sean integers (o strings que se conviertan a integers) y los números
sean divisibles, en cuyo caso será devuelto un valor integer.
</simpara>
<simpara>
Los operandos del módulo se convierten en integers (por extracción de la parte
decimal) antes del procesamiento.
</simpara>
<para>
El resultado del operador módulo <literal>%</literal> tiene el mismo signo
que el dividendo — es decir, el resultado de <literal>$a % $b</literal>
tendrá el mismo signo que <varname>$a</varname>. Por ejemplo:
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
echo (5 % 3)."\n"; // muestra 2
echo (5 % -3)."\n"; // muestra 2
echo (-5 % 3)."\n"; // muestra -2
echo (-5 % -3)."\n"; // muestra -2
?>
]]>
</programlisting>
</informalexample>
</para>
<simpara>
Véase también la página del manual sobre
<link linkend="ref.math">funciones matemáticas</link>.
</simpara>
</sect1>
<sect1 xml:id="language.operators.assignment">
<title>Operadores de asignación</title>
<simpara>
El operador básico de asignación es "=". Se podría inclinar a pensar
primero que es como un "igual a". No lo es. Realmente significa que el
operando de la izquierda se establece con el valor de la expresión de la
derecha (es decir, "se define como").
</simpara>
<para>
El valor de una expresión de asignación es el valor asignado. Es
decir, el valor de "<literal>$a = 3</literal>" es de 3. Esto permite hacer algunas cosas
intrincadas:
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
$a = ($b = 4) + 5; // ahora $a es igual a 9 y $b se ha establecido en 4.
?>
]]>
</programlisting>
</informalexample>
</para>
<para>
Para <type>arrays</type>, asignar un valor a una clave con nombre se realiza utilizando
el operador "=&gt;". La <link linkend="language.operators.precedence">precedencia</link>
de este operador es la misma que otros operadores de asignación.
</para>
<para>
Además del operador básico de asignación, existen "operadores
combinados" para todos los de <link linkend="language.operators">aritmética
binaria</link>, unión de arrays y operadores de strings que permiten usar un valor en una
expresión y entonces establecer su valor como el resultado de esa expresión. Por
ejemplo:
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
$a = 3;
$a += 5; // establece $a en 8, como si se hubiera dicho: $a = $a + 5;
$b = "Hola ";
$b .= "ahí!"; // establece $b en "Hola ahí!", al igual que $b = $b . "ahí!";
?>
]]>
</programlisting>
</informalexample>
</para>
<para>
Observe que la asignación copia la variable original en la nueva
(asignación por valor), por lo que los cambios en una no afectarán a la
otra. Esto también puede tener relevancia si se necesita copiar algo
como un gran array dentro de un bucle estrecho.
</para>
<para>
Una excepción al comportamiento usual de la asignación por valor en PHP ocurre
con <type>object</type>s los cuales son asignados por referencia en PHP 5.
Los objetos pueden ser explícitamente copiados por medio de la palabra clave
<link linkend="language.oop5.cloning">clone</link>.
</para>
<sect2 xml:id="language.operators.assignment.reference">
<title>Asignación por referencia</title>
<para>
La asignación por referencia también está soportada, utilizando la
sintaxis "<computeroutput>$var = &amp;$othervar;</computeroutput>".
Asignación por referencia significa que ambas variables terminan apuntando a los
mismos datos y nada es copiado en ninguna parte.
</para>
<para>
<example>
<title>Asignación por referencia</title>
<programlisting role="php">
<![CDATA[
<?php
$a = 3;
$b = &$a; // $b es una referencia para $a
print "$a\n"; // muestra 3
print "$b\n"; // muestra 3
$a = 4; // cambia $a
print "$a\n"; // muestra 4
print "$b\n"; // muestra 4 también, dado que $b es una referencia para $a, la cual ha
// sido cambiada
?>
]]>
</programlisting>
</example>
</para>
<para>
Desde PHP 5, el operador <link linkend="language.oop5.basic.new">new</link>
retorna una referencia automáticamente, así que asignar el resultado de
<link linkend="language.oop5.basic.new">new</link> por referencia, resulta
en un mensaje <constant>E_DEPRECATED</constant> en PHP 5.3 y posteriores y
un mensaje <constant>E_STRICT</constant> en versiones anteriores.
</para>
<para>
Por ejemplo, éste código resultará en una advertencia:
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
class C {}
/* La siguiente línea genera el siguiente mensaje de error:
* Deprecated: Assigning the return value of new by reference is deprecated in...
*/
$o = &new C;
?>
]]>
</programlisting>
</informalexample>
</para>
<para>
Más información sobre referencias y sus usos potenciales se puede encontrar en
la sección del manual
<link linkend="language.references">Referencias Explicadas</link>
</para>
</sect2>
</sect1>
<sect1 xml:id="language.operators.bitwise">
<title>Operadores bit a bit</title>
<simpara>
Los operadores bit a bit permiten la evaluación y la manipulación de bits
específicos dentro de un integer.
</simpara>
<table>
<title>Operadores bit a bit</title>
<tgroup cols="3">
<thead>
<row>
<entry>Ejemplo</entry>
<entry>Nombre</entry>
<entry>Resultado</entry>
</row>
</thead>
<tbody>
<row>
<entry><userinput>$a &amp; $b</userinput></entry>
<entry>And (y)</entry>
<entry>Los bits que están activos en ambos <varname>$a</varname> y <varname>$b</varname> son activados.</entry>
</row>
<row>
<entry><userinput>$a | $b</userinput></entry>
<entry>Or (o inclusivo)</entry>
<entry>Los bits que están activos ya sea en <varname>$a</varname> o en <varname>$b</varname> son activados.</entry>
</row>
<row>
<entry><userinput>$a ^ $b</userinput></entry>
<entry>Xor (o exclusivo)</entry>
<entry>
Los bits que están activos en <varname>$a</varname> o en <varname>$b</varname>, pero no en ambos, son activados.
</entry>
</row>
<row>
<entry><userinput>~ $a</userinput></entry>
<entry>Not (no)</entry>
<entry>
Los bits que están activos en <varname>$a</varname> son desactivados, y viceversa.
</entry>
</row>
<row>
<entry><userinput>$a &lt;&lt; $b</userinput></entry>
<entry>Shift left(desplazamiento a izquierda)</entry>
<entry>
Desplaza los bits de <varname>$a</varname>, <varname>$b</varname> pasos a la izquierda (cada paso
quiere decir "multiplicar por dos").
</entry>
</row>
<row>
<entry><userinput>$a &gt;&gt; $b</userinput></entry>
<entry>Shift right (desplazamiento a derecha)</entry>
<entry>
Desplaza los bits de <varname>$a</varname>, <varname>$b</varname> pasos a la derecha (cada paso
quiere decir "dividir por dos").
</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
El desplazamiento de bits en PHP es aritmético.
Los bits desplazados por fuera de cualquiera de los extremos son descartados.
Desplazamientos de izquierda tienen ceros desplazados a la derecha mientras que el
bit de signo es desplazado fuera a la izquierda, es decir que no se conserva el
signo de un operando.
Desplazamientos a la derecha tienen copias del bit de signo desplazado a la izquierda,
es decir que se conserva el signo de un operando.
</para>
<para>
Utilice paréntesis para garantizar la
<link linkend="language.operators.precedence">precedencia</link> deseada.
Por ejemplo, <literal>$a &amp; $b == true</literal> evalúa
la equivalencia y luego el bit a bit, mientras que
<literal>($a &amp; $b) == true</literal> evalúa el bit a bit y
luego la equivalencia.
</para>
<para>
Si los operandos para los operadores <literal>&amp;</literal>, <literal>|</literal> y
<literal>^</literal> son string, la operación se realizará
con los valores ASCII de los caracteres que componen dichos string, y el
resultado será también un string. En todos los demás casos, ambos operandos serán
<link linkend="language.types.integer.casting">convertidos a valores de tipo integer</link>
y el resultado será también un integer.
</para>
<para>
Si el operando del operados <literal>~</literal> es un string, la
operación se realizará con valores los ASCII de los caracteres que componen
dicho string, y el resultado también será un string; en caso contrario, el operando y
el resultado serán tratados como valores de tipo integer.
</para>
<para>
Ambos operandos y el resultado de lo operadores <literal>&lt;&lt;</literal> y
<literal>&gt;&gt;</literal> siempre son tratados como valores de tipo integer.
</para>
<para>
<informalexample>
<para>
<literallayout>
El ajuste ini error_reporting utiliza valores a nivel de bit,
lo que ofrece una demostración del mundo real de desactivar
bits. Para mostrar todos los errores, a excepción de los avisos,
las instrucciones del archivo php.ini dicen utilizar:
<userinput>E_ALL &amp; ~E_NOTICE</userinput>
</literallayout>
</para>
<para>
<literallayout>
Esto funciona iniciando con E_ALL:
<computeroutput>00000000000000000111011111111111</computeroutput>
Luego se toma el valor de E_NOTICE ...
<computeroutput>00000000000000000000000000001000</computeroutput>
... y se invierte por medio de <literal>~</literal>:
<computeroutput>11111111111111111111111111110111</computeroutput>
Finalmente, se utiliza AND (&amp;) para encontrar los bits que se
activaron en ambos valores:
<computeroutput>00000000000000000111011111110111</computeroutput>
</literallayout>
</para>
<para>
<literallayout>
Otra forma de lograrlo es mediante XOR (<literal>^</literal>)
para encontrar los bits que están activados en sólo el primer valor o en el otro:
<userinput>E_ALL ^ E_NOTICE</userinput>
</literallayout>
</para>
</informalexample>
</para>
<para>
<informalexample>
<para>
<literallayout>
error_reporting también se puede utilizar para demostrar la activación de bits.
La forma para mostrar sólo los errores y los errores recuperables es:
<userinput>E_ERROR | E_RECOVERABLE_ERROR</userinput>
</literallayout>
</para>
<para>
<literallayout>
Este proceso combina E_ERROR
<computeroutput>00000000000000000000000000000001</computeroutput>
y
<computeroutput>00000000000000000001000000000000</computeroutput>
usando el operador OR (<literal>|</literal>)
para obtener los bits activados en cualquiera de estos valores:
<computeroutput>00000000000000000001000000000001</computeroutput>
</literallayout>
</para>
</informalexample>
</para>
<para>
<example>
<title>Operaciones AND, OR y XOR bit a bit sobre integers</title>
<programlisting role="php">
<![CDATA[
<?php
/*
* Ignore la sección superior,
* es sólo el formateado para hacer la salida más clara.
*/
$format = '(%1$2d = %1$04b) = (%2$2d = %2$04b)'
. ' %3$s (%4$2d = %4$04b)' . "\n";
echo <<<EOH
--------- --------- -- ---------
resultado valor op prueba
--------- --------- -- ---------
EOH;
/*
* Aquí están los ejemplos.
*/
$values = array(0, 1, 2, 4, 8);
$test = 1 + 4;
echo "\n AND bit a bit \n";
foreach ($values as $value) {
$result = $value & $test;
printf($format, $result, $value, '&', $test);
}
echo "\n OR inclusivo bit a bit \n";
foreach ($values as $value) {
$result = $value | $test;
printf($format, $result, $value, '|', $test);
}
echo "\n OR exclusivo (XOR) bit a bit \n";
foreach ($values as $value) {
$result = $value ^ $test;
printf($format, $result, $value, '^', $test);
}
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
--------- --------- -- ---------
resultado valor op prueba
--------- --------- -- ---------
AND bit a bit
( 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)
OR inclusivo bit a bit
( 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)
OR exclusivo (XOR) bit a bit
( 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>Operaciones XOR bit a bit sobre strings</title>
<programlisting role="php">
<![CDATA[
<?php
echo 12 ^ 9; // Sale '5'
echo "12" ^ "9"; // Sale el caracter de retroceso (ascii 8)
// ('1' (ascii 49)) ^ ('9' (ascii 57)) = #8
echo "hallo" ^ "hello"; // Salen los valores ascii #0 #4 #0 #0 #0
// 'a' ^ 'e' = #4
echo 2 ^ "3"; // Sale 1
// 2 ^ ((int)"3") == 1
echo "2" ^ 3; // Sale 1
// ((int)"2") ^ 3 == 1
?>
]]>
</programlisting>
</example>
</para>
<para>
<example>
<title>Desplazamiento de bits sobre integers</title>
<programlisting role="php">
<![CDATA[
<?php
/*
* Aquí están los ejemplos.
*/
echo "\n--- DESPLAZAMIENTO DE BITS A LA DERECHA SOBRE ENTEROS POSITIVOS ---\n";
$val = 4;
$places = 1;
$res = $val >> $places;
p($res, $val, '>>', $places, 'copia del bit de signo desplazado hacia el lado izquierdo');
$val = 4;
$places = 2;
$res = $val >> $places;
p($res, $val, '>>', $places);
$val = 4;
$places = 3;
$res = $val >> $places;
p($res, $val, '>>', $places, 'bits desplazados fuera del lado derecho');
$val = 4;
$places = 4;
$res = $val >> $places;
p($res, $val, '>>', $places, 'mismo resultado que arriba; no se puede desplazar más allá del 0');
echo "\n--- DESPLAZAMIENTO DE BITS A LA DERECHA SOBRE ENTEROS NEGATIVOS ---\n";
$val = -4;
$places = 1;
$res = $val >> $places;
p($res, $val, '>>', $places, 'copia del bit de signo desplazado al lado izquierdo');
$val = -4;
$places = 2;
$res = $val >> $places;
p($res, $val, '>>', $places, 'bits desplazados fuera del lado derecho');
$val = -4;
$places = 3;
$res = $val >> $places;
p($res, $val, '>>', $places, 'mismo resultado que arriba; no se puede desplazar más allá del -1');
echo "\n--- DESPLAZAMIENTO DE BITS A LA IZQUIERDA SOBRE ENTEROS POSITIVOS ---\n";
$val = 4;
$places = 1;
$res = $val << $places;
p($res, $val, '<<', $places, 'ceros rellenan en el lado derecho');
$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, 'bit de signo resulta desplazado fuera');
$val = 4;
$places = (PHP_INT_SIZE * 8) - 2;
$res = $val << $places;
p($res, $val, '<<', $places, 'bit de signo desplazado fuera del lado izquierdo');
echo "\n--- DESPLAZAMIENTO DE BITS A LA IZQUIERDA SOBRE ENTEROS NEGATIVOS ---\n";
$val = -4;
$places = 1;
$res = $val << $places;
p($res, $val, '<<', $places, 'ceros rellenan en el lado derecho');
$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 desplazados fuera del lado izquierdo, incluyendo el bit de signo');
/*
* 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[
--- DESPLAZAMIENTO DE BITS A LA DERECHA SOBRE ENTEROS POSITIVOS ---
Expression: 2 = 4 >> 1
Decimal:
val=4
res=2
Binary:
val=00000000000000000000000000000100
res=00000000000000000000000000000010
NOTE: copia del bit de signo desplazado hacia el lado izquierdo
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 desplazados fuera del lado derecho
Expression: 0 = 4 >> 4
Decimal:
val=4
res=0
Binary:
val=00000000000000000000000000000100
res=00000000000000000000000000000000
NOTE: mismo resultado que arriba; no se puede desplazar más allá del 0
--- DESPLAZAMIENTO DE BITS A LA DERECHA SOBRE ENTEROS NEGATIVOS ---
Expression: -2 = -4 >> 1
Decimal:
val=-4
res=-2
Binary:
val=11111111111111111111111111111100
res=11111111111111111111111111111110
NOTE: copia del bit de signo desplazado al lado izquierdo
Expression: -1 = -4 >> 2
Decimal:
val=-4
res=-1
Binary:
val=11111111111111111111111111111100
res=11111111111111111111111111111111
NOTE: bits desplazados fuera del lado derecho
Expression: -1 = -4 >> 3
Decimal:
val=-4
res=-1
Binary:
val=11111111111111111111111111111100
res=11111111111111111111111111111111
NOTE: mismo resultado que arriba; no se puede desplazar más allá del -1
--- DESPLAZAMIENTO DE BITS A LA IZQUIERDA SOBRE ENTEROS POSITIVOS ---
Expression: 8 = 4 << 1
Decimal:
val=4
res=8
Binary:
val=00000000000000000000000000000100
res=00000000000000000000000000001000
NOTE: ceros rellenan en el lado derecho
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: bit de signo resulta desplazado fuera
Expression: 0 = 4 << 30
Decimal:
val=4
res=0
Binary:
val=00000000000000000000000000000100
res=00000000000000000000000000000000
NOTE: bit de signo desplazado fuera del lado izquierdo
--- DESPLAZAMIENTO DE BITS A LA IZQUIERDA SOBRE ENTEROS NEGATIVOS ---
Expression: -8 = -4 << 1
Decimal:
val=-4
res=-8
Binary:
val=11111111111111111111111111111100
res=11111111111111111111111111111000
NOTE: ceros rellenan en el lado derecho
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 desplazados fuera del lado izquierdo, incluyendo el bit de signo
]]>
</screen>
&example.outputs.64bit;
<screen>
<![CDATA[
--- DESPLAZAMIENTO DE BITS A LA DERECHA SOBRE ENTEROS POSITIVOS ---
Expression: 2 = 4 >> 1
Decimal:
val=4
res=2
Binary:
val=0000000000000000000000000000000000000000000000000000000000000100
res=0000000000000000000000000000000000000000000000000000000000000010
NOTE: copia del bit de signo desplazado hacia el lado izquierdo
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 desplazados fuera del lado derecho
Expression: 0 = 4 >> 4
Decimal:
val=4
res=0
Binary:
val=0000000000000000000000000000000000000000000000000000000000000100
res=0000000000000000000000000000000000000000000000000000000000000000
NOTE: mismo resultado que arriba; no se puede desplazar más allá del 0
--- DESPLAZAMIENTO DE BITS A LA DERECHA SOBRE ENTEROS NEGATIVOS ---
Expression: -2 = -4 >> 1
Decimal:
val=-4
res=-2
Binary:
val=1111111111111111111111111111111111111111111111111111111111111100
res=1111111111111111111111111111111111111111111111111111111111111110
NOTE: copia del bit de signo desplazado al lado izquierdo
Expression: -1 = -4 >> 2
Decimal:
val=-4
res=-1
Binary:
val=1111111111111111111111111111111111111111111111111111111111111100
res=1111111111111111111111111111111111111111111111111111111111111111
NOTE: bits desplazados fuera del lado derecho
Expression: -1 = -4 >> 3
Decimal:
val=-4
res=-1
Binary:
val=1111111111111111111111111111111111111111111111111111111111111100
res=1111111111111111111111111111111111111111111111111111111111111111
NOTE: mismo resultado que arriba; no se puede desplazar más allá del -1
--- DESPLAZAMIENTO DE BITS A LA IZQUIERDA SOBRE ENTEROS POSITIVOS ---
Expression: 8 = 4 << 1
Decimal:
val=4
res=8
Binary:
val=0000000000000000000000000000000000000000000000000000000000000100
res=0000000000000000000000000000000000000000000000000000000000001000
NOTE: ceros rellenan en el lado derecho
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: bit de signo resulta desplazado fuera
Expression: 0 = 4 << 62
Decimal:
val=4
res=0
Binary:
val=0000000000000000000000000000000000000000000000000000000000000100
res=0000000000000000000000000000000000000000000000000000000000000000
NOTE: bit de signo desplazado fuera del lado izquierdo
--- DESPLAZAMIENTO DE BITS A LA IZQUIERDA SOBRE ENTEROS NEGATIVOS ---
Expression: -8 = -4 << 1
Decimal:
val=-4
res=-8
Binary:
val=1111111111111111111111111111111111111111111111111111111111111100
res=1111111111111111111111111111111111111111111111111111111111111000
NOTE: ceros rellenan en el lado derecho
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 desplazados fuera del lado izquierdo, incluyendo el bit de signo
]]>
</screen>
</example>
</para>
<warning>
<para>
Desplazar un integer por valores mayores o iguales al ancho del tipo long integer
del sistema resultará en un comportamiento indefinido. En otras palabras, no desplace
más de 31 bit en sistemas de 32 bit, y no desplace más de 63 bit en sistemas
de 64 bit.
</para>
<para>
Use funciones de la extensión <link linkend="book.gmp">gmp</link> para
manipular a nivel de bit números mayores que <literal>PHP_INT_MAX</literal>.
</para>
</warning>
<para>
Ver también
<function>pack</function>,
<function>unpack</function>,
<function>gmp_and</function>,
<function>gmp_or</function>,
<function>gmp_xor</function>,
<function>gmp_testbit</function>,
<function>gmp_clrbit</function>
</para>
</sect1>
<sect1 xml:id="language.operators.comparison">
<title>Operadores de comparación</title>
<simpara>
Los operadores de comparación, como su nombre lo indica, permiten comparar
dos valores. Puede también estar interesado en ver
<link linkend="types.comparisons">las tablas de comparación de tipos</link>,
ya que muestran ejemplos de las varias comparaciones relacionadas con tipos.
</simpara>
<table>
<title>Operadores de comparación</title>
<tgroup cols="3">
<thead>
<row>
<entry>Ejemplo</entry>
<entry>Nombre</entry>
<entry>Resultado</entry>
</row>
</thead>
<tbody>
<row>
<entry>$a == $b</entry>
<entry>Igual</entry>
<entry>&true; si <varname>$a</varname> es igual a <varname>$b</varname> después de la manipulación de tipos.</entry>
</row>
<row>
<entry>$a === $b</entry>
<entry>Idéntico</entry>
<entry>
&true; si <varname>$a</varname> es igual a <varname>$b</varname>, y son del mismo
tipo.
</entry>
</row>
<row>
<entry>$a != $b</entry>
<entry>Diferente</entry>
<entry>&true; si <varname>$a</varname> no es igual a <varname>$b</varname> después de la manipulación de tipos.</entry>
</row>
<row>
<entry>$a &lt;&gt; $b</entry>
<entry>Diferente</entry>
<entry>&true; si <varname>$a</varname> no es igual a <varname>$b</varname> después de la manipulación de tipos.</entry>
</row>
<row>
<entry>$a !== $b</entry>
<entry>No idéntico</entry>
<entry>
&true; si <varname>$a</varname> no es igual a <varname>$b</varname>, o si no son del mismo
tipo.
</entry>
</row>
<row>
<entry>$a &lt; $b</entry>
<entry>Menor que</entry>
<entry>&true; si <varname>$a</varname> es estrictamente menor que <varname>$b</varname>.</entry>
</row>
<row>
<entry>$a &gt; $b</entry>
<entry>Mayor que</entry>
<entry>&true; si <varname>$a</varname> es estrictamente mayor que <varname>$b</varname>.</entry>
</row>
<row>
<entry>$a &lt;= $b</entry>
<entry>Menor o igual que</entry>
<entry>&true; si <varname>$a</varname> es menor o igual que <varname>$b</varname>.</entry>
</row>
<row>
<entry>$a &gt;= $b</entry>
<entry>Mayor o igual que</entry>
<entry>&true; si <varname>$a</varname> es mayor o igual que <varname>$b</varname>.</entry>
</row>
<row>
<entry>$a &lt;=&gt; $b</entry>
<entry>Nave espacial</entry>
<entry>
Un <type>integer</type> menor que, igual a, o mayor que cero cuando
<varname>$a</varname> es respectivamente menor que, igual a, o mayor
que <varname>$b</varname>. Disponible a partir de PHP 7.
</entry>
</row>
<row>
<entry>$a ?? $b ?? $c</entry>
<entry>Fusión de null</entry>
<entry>
El primer operando de izquierda a derecha que exista y no sea &null;.
&null; si no hay valores definidos y no son &null;. Disponible a partir de PHP 7.
</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
Si se compara un número con un string o la comparación implica strings
numéricos, entonces cada string es
<link linkend="language.types.string.conversion">convertido en un número</link>
y la comparación realizada numéricamente. Estas reglas también se aplican a la sentencia
<link linkend="control-structures.switch">switch</link>. La
conversión de tipo no tiene lugar cuando la comparación es === o !== ya que
esto involucra comparar el tipo así como el valor.
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
var_dump(0 == "a"); // 0 == 0 -> true
var_dump("1" == "01"); // 1 == 1 -> true
var_dump("10" == "1e1"); // 10 == 10 -> true
var_dump(100 == "1e2"); // 100 == 100 -> true
switch ("a") {
case 0:
echo "0";
break;
case "a": // nunca alcanzado debido a que "a" ya ha coincidido con 0
echo "a";
break;
}
?>
]]>
</programlisting>
<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
// only values are compared
$a = (object) ["a" => "b"];
$b = (object) ["b" => "b"];
echo $a <=> $b; // 1
?>
]]>
</programlisting>
</informalexample>
</para>
<para>
Para varios tipos, la comparación se realiza de acuerdo a la siguiente
tabla (en orden).
</para>
<table xml:id="language.operators.comparison.types">
<title>La comparación con varios tipos</title>
<tgroup cols="3">
<thead>
<row>
<entry>Tipo de operando 1</entry>
<entry>Tipo de operando 2</entry>
<entry>Resultado</entry>
</row>
</thead>
<tbody>
<row>
<entry><type>null</type> o <type>string</type></entry>
<entry><type>string</type></entry>
<entry>Convierte &null; en "", comparación numérica o léxica</entry>
</row>
<row>
<entry><type>bool</type> o <type>null</type></entry>
<entry>cualquiera</entry>
<entry>Convierte ambos lados a <type>bool</type>, &false; &lt; &true;</entry>
</row>
<row>
<entry><type>object</type></entry>
<entry><type>object</type></entry>
<entry>Las clases internas pueden definir su propia comparación, diferentes clases
son incomparables, la misma clase - comparan propiedades en la misma forma que
los arrays (PHP 4), PHP 5 tiene su propia <link
linkend="language.oop5.object-comparison">explicación</link>
</entry>
</row>
<row>
<entry><type>string</type>, <type>resource</type> o <type>number</type></entry>
<entry><type>string</type>, <type>resource</type> o <type>number</type></entry>
<entry>Traducir las cadenas y recursos a números, matemática usual</entry>
</row>
<row>
<entry><type>array</type></entry>
<entry><type>array</type></entry>
<entry>Un array con menos elementos es menor, si una clave del operando 1 no se
encuentra en el operando 2 entonces los arrays son incomparables, de otra forma - compara
valor por valor (ver el siguiente ejemplo)</entry>
</row>
<row>
<entry><type>object</type></entry>
<entry>cualquiera</entry>
<entry><type>object</type> es siempre mayor</entry>
</row>
<row>
<entry><type>array</type></entry>
<entry>cualquiera</entry>
<entry><type>array</type> es siempre mayor</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
<example>
<title>Comparación boolean/null</title>
<programlisting role="php">
<![CDATA[
<?php
// Booleanos y null son comparados siempre coomo bool
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>Transcripción de la comparación estándar de arrays</title>
<programlisting role="php">
<![CDATA[
<?php
// Arrays son comparados de esta forma con los operadores de comparación estándar
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>
<para>
Ver también <function>strcasecmp</function>,
<function>strcmp</function>,
<link linkend="language.operators.array">operadores de array</link>,
y la sección del manual sobre
<link linkend="language.types">tipos</link>.
</para>
<warning>
<title>Comparación de números de punto flotante</title>
<para>
Debido a la forma en que son representados internamente los <type>float</type>s, no
se deben probar por igualdad dos <type>float</type>s.
</para>
<para>
Ver la documentación de <type>float</type> para más información.
</para>
</warning>
<sect2 xml:id="language.operators.comparison.ternary">
<title>Operador ternario</title>
<para>
Otro operador condicional es el operador "?:" (o ternario).
<example>
<title>Asignación de un valor predeterminado</title>
<programlisting role="php">
<![CDATA[
<?php
// Ejemplo de uso para: Operador Ternario
$action = (empty($_POST['action'])) ? 'default' : $_POST['action'];
// Lo anterior es idéntico a esta sentencia if/else
if (empty($_POST['action'])) {
$action = 'default';
} else {
$action = $_POST['action'];
}
?>
]]>
</programlisting>
</example>
La expresión <literal>(expr1) ? (expr2) : (expr3)</literal>
evalúa a <replaceable>expr2</replaceable> si
<replaceable>expr1</replaceable> se evalúa como &true; y a
<replaceable>expr3</replaceable> si
<replaceable>expr1</replaceable> se evalúa como &false;.
</para>
<para>
A partir de PHP 5.3, es posible dejar de lado la parte media del operador
ternario. La expresión <literal>expr1 ?: expr3</literal> retorna
<replaceable>expr1</replaceable> si <replaceable>expr1</replaceable>
se evalúa como &true; y <replaceable>expr3</replaceable> si es de otra manera.
</para>
<note>
<simpara>
Por favor note que el operador ternario es una expresión, y que
no evalúa a una variable, sino al resultado de una expresión. Esto
es importante saberlo si se desea retornar una variable por referencia.
La sentencia <literal>return $var == 42 ? $a : $b;</literal> en una
función con retorno-por-referencia no funcionará por lo que se ha mencionado y una advertencia es
generada en versiones posteriores de PHP.
</simpara>
</note>
<note>
<para>
Es recomendable evitar el "apilamiento" expresiones ternarias. El
comportamiento de PHP al utilizar más de un operador ternario en una única
sentencia no es evidente:
<example>
<title>Comportamiento Ternario poco obvio</title>
<programlisting role="php">
<![CDATA[
<?php
// a primera vista, lo siguiente parece tener la salida de 'true'
echo (true?'true':false?'t':'f');
// sin embargo, la salida real de lo anterior es 't'
// esto se debe a que las expresiones ternarias se evalúan de izquierda a derecha
// la siguiente es una versión más obvia del mismo código anterior
echo ((true ? 'true' : false) ? 't' : 'f');
// aquí, se puede ver que la primera expresión es evaluada como 'true', que
// a su vez se evalúa como (bool)true, retornando así la rama verdadera de la
// segunda expresión ternaria.
?>
]]>
</programlisting>
</example>
</para>
</note>
</sect2>
</sect1>
<sect1 xml:id="language.operators.errorcontrol">
<title>Operadores de control de errores</title>
<simpara>
PHP soporta un operador de control de errores: el signo de arroba (@). Cuando
se antepone a una expresión en PHP, cualquier mensaje de error que pueden
ser generado por esa expresión será ignorado.
</simpara>
<simpara>
Si se ha establecido una función controladora de errores personalizada con
<function>set_error_handler</function> entonces todavía será
llamada, pero este controlador de errores personalizado puede (y debe) llamar a <function>error_reporting</function>
el cual devolverá 0 cuando la llamada que provocó el error fue precedida por el signo @.
</simpara>
<simpara>
Si la propiedad <link linkend="ini.track-errors"><option>track_errors</option></link>
está activada, cualquier mensaje de error generado por la expresión
será guardada en la variable
<varname>$php_errormsg</varname>.
Esta variable se sobrescribe en cada error, así que se debe comprobar antes si
se desea utilizar.
</simpara>
<para>
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
/* Error intencional de archivo */
$my_file = @file ('non_existent_file') or
die ("La apertura de archivo ha fallado: el error fue '$php_errormsg'");
// esto funciona con cualquier expresión, no solo con funciones:
$value = @$cache[$key];
// no producirá una anotación si el índice $key no existe.
?>
]]>
</programlisting>
</informalexample>
</para>
<note>
<simpara>
El operador @ trabaja sólo sobre
<link linkend="language.expressions">expresiones</link>. Una simple regla
de oro es: si se puede tomar el valor de algo, entonces se le puede anteponer
el operador @. Por ejemplo, puede anteponerse a variables,
a llamadas a funciones e <function>include</function>s, constantes y
así sucesivamente. No puede anteponerse a definiciones de función o clase,
ni a estructuras condicionales como <literal>if</literal> y
&foreach;, y así sucesivamente.
</simpara>
</note>
<simpara>
Ver también <function>error_reporting</function> y la sección del manual sobre
<link linkend="ref.errorfunc">funciones de Manejo de Errores y Registros</link>.
</simpara>
<warning>
<para>
En la actualidad, el operador de prefijo "@" para control de errores deshabilitará incluso
el reporte de errores en casos de fallos críticos que terminarán la ejecución del
script. Entre otras cosas, esto quiere decir que si se usa "@" para
eliminar los errores de una cierta función y ésta no se encuentra
disponible o ha sido escrita de forma incorrecta, el script se detendrá en ese punto
sin indicación de por qué.
</para>
</warning>
</sect1>
<sect1 xml:id="language.operators.execution">
<title>Operadores de ejecución</title>
<para>
PHP soporta un operador de ejecución: las comillas invertidas (``). ¡Note que
estas no son las comillas sencillas! PHP intentará ejecutar el
contenido entre las comillas invertidas como si se tratara de un comando del shell; la salida será
retornada (es decir, no será simplemente volcada como salida; puede ser
asignada a una variable). El uso del operador de comillas invertidas es idéntico
al de <function>shell_exec</function>.
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
$output = `ls -al`;
echo "<pre>$output</pre>";
?>
]]>
</programlisting>
</informalexample>
</para>
<note>
<para>
El operador de comillas invertidas se deshabilita cuando &safemode; esta activado
o <function>shell_exec</function> esta desactivado.
</para>
</note>
<note>
<para>
A diferencia de otros lenguajes, las comillas invertidas no tienen un significa especial
dentro de string entre comillas dobles.
</para>
</note>
<para>
Vea también la sección del manual sobre <link linkend="ref.exec">funciones
de ejecución de programas</link>, <function>popen</function>
<function>proc_open</function> y
<link linkend="features.commandline">Usando PHP desde la
línea de comandos</link>.
</para>
</sect1>
<sect1 xml:id="language.operators.increment">
<title>Operadores de incremento/decremento</title>
<para>
PHP soporta operadores estilo C de pre- y post-incremento
y decremento.
</para>
<note>
<simpara>
Los operadores de incremento/decremento solamente afectan a números y strings.
Los arrays, objects y resources no se ven afectados.
Decrementar valores &null; tampoco tiene efecto, pero incrementarlos entonces
resulta en <literal>1</literal>.
</simpara>
</note>
<table>
<title>Operadores de incremento/decremento</title>
<tgroup cols="3">
<thead>
<row>
<entry>Ejemplo</entry>
<entry>Nombre</entry>
<entry>Efecto</entry>
</row>
</thead>
<tbody>
<row>
<entry>++$a</entry>
<entry>Pre-incremento</entry>
<entry>Incrementa <varname>$a</varname> en uno, y luego retorna <varname>$a</varname>.</entry>
</row>
<row>
<entry>$a++</entry>
<entry>Post-incremento</entry>
<entry>Retorna <varname>$a</varname>, y luego incrementa <varname>$a</varname> en uno.</entry>
</row>
<row>
<entry>--$a</entry>
<entry>Pre-decremento</entry>
<entry>Decrementa <varname>$a</varname> en uno, luego retorna <varname>$a</varname>.</entry>
</row>
<row>
<entry>$a--</entry>
<entry>Post-decremento</entry>
<entry>Retorna <varname>$a</varname>, luego decrementa <varname>$a</varname> en uno.</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
Aquí hay un script simple de ejemplo:
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
echo "<h3>Postincremento</h3>";
$a = 5;
echo "Debe ser 5: " . $a++ . "<br />\n";
echo "Debe ser 6: " . $a . "<br />\n";
echo "<h3>Preincremento</h3>";
$a = 5;
echo "Debe ser 6: " . ++$a . "<br />\n";
echo "Debe ser 6: " . $a . "<br />\n";
echo "<h3>Postdecremento</h3>";
$a = 5;
echo "Debe ser 5: " . $a-- . "<br />\n";
echo "Debe ser 4: " . $a . "<br />\n";
echo "<h3>Predecremento</h3>";
$a = 5;
echo "Debe ser 4: " . --$a . "<br />\n";
echo "Debe ser 4: " . $a . "<br />\n";
?>
]]>
</programlisting>
</informalexample>
</para>
<para>
PHP sigue la convención de Perl cuando trabaja con operaciones aritméticas
sobre variables de caracteres y no la de C. Por ejemplo, en PHP y Perl
<literal>$a = 'Z'; $a++;</literal> convierte <literal>$a</literal> en <literal>'AA'</literal>, mientras que en C
<literal>a = 'Z'; a++;</literal> convierte <literal>a</literal> en <literal>'['</literal>
(el valor ASCII de <literal>'Z'</literal> es 90, el valor ASCII de <literal>'['</literal> es 91).
Nótese que las variables de caracteres pueden ser incrementadas pero no decrementadas y
aun así sólo caracteres y dígitos de ASCII puro (a-z, A-Z y 0-9) están soportados.
Incrementar o decrementar otras variables de caracteres no tiene efecto, el
string original no se modifica.
<example>
<title>Operaciones aritméticas sobre variables de caracteres</title>
<programlisting role="php">
<![CDATA[
<?php
echo '== Letras ==' . PHP_EOL;
$s = 'W';
for ($n=0; $n<6; $n++) {
echo ++$s . PHP_EOL;
}
// Los caracteres de dígitos tienen un comportamiento diferente
echo '== Dígitos ==' . 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[
== Letras ==
X
Y
Z
AA
AB
AC
== Dígitos ==
A9
B0
B1
B2
B3
B4
A09
A10
A11
A12
A13
A14
]]>
</screen>
</example>
</para>
<para>
Incrementar o decrementar booleanos no tiene efecto.
</para>
</sect1>
<sect1 xml:id="language.operators.logical">
<title>Operadores lógicos</title>
<table>
<title>Operadores lógicos</title>
<tgroup cols="3">
<thead>
<row>
<entry>Ejemplo</entry>
<entry>Nombre</entry>
<entry>Resultado</entry>
</row>
</thead>
<tbody>
<row>
<entry>$a and $b</entry>
<entry>And (y)</entry>
<entry>&true; si tanto <varname>$a</varname> como <varname>$b</varname> son &true;.</entry>
</row>
<row>
<entry>$a or $b</entry>
<entry>Or (o inclusivo)</entry>
<entry>&true; si cualquiera de <varname>$a</varname> o <varname>$b</varname> es &true;.</entry>
</row>
<row>
<entry>$a xor $b</entry>
<entry>Xor (o exclusivo)</entry>
<entry>&true; si <varname>$a</varname> o <varname>$b</varname> es &true;, pero no ambos.</entry>
</row>
<row>
<entry>! $a</entry>
<entry>Not (no)</entry>
<entry>&true; si <varname>$a</varname> no es &true;.</entry>
</row>
<row>
<entry>$a &amp;&amp; $b</entry>
<entry>And (y)</entry>
<entry>&true; si tanto <varname>$a</varname> como <varname>$b</varname> son &true;.</entry>
</row>
<row>
<entry>$a || $b</entry>
<entry>Or (o inclusivo)</entry>
<entry>&true; si cualquiera de <varname>$a</varname> o <varname>$b</varname> es &true;.</entry>
</row>
</tbody>
</tgroup>
</table>
<simpara>
La razón para tener las dos variaciones diferentes de los operadores
"and" y "or" es que ellos operan con precedencias diferentes. (Ver
<link linkend="language.operators.precedence">Precedencia
de operadores</link>.)
</simpara>
<example>
<title>Los operadores lógicos ilustrados</title>
<programlisting role="php">
<![CDATA[
<?php
// --------------------
// foo() nunca será llamado ya que los operadores están en cortocircuito
$a = (false && foo());
$b = (true || foo());
$c = (false and foo());
$d = (true or foo());
// --------------------
// "||" tiene una precedencia mayor que "or"
// El resultado de la expresión (false || true) es asignado a $e
// Actúa como: ($e = (false || true))
$e = false || true;
// La constante false es asignada a $f antes de que suceda la operación "or"
// Actúa como: (($f = false) or true)
$f = false or true;
var_dump($e, $f);
// --------------------
// "&&" tiene una precedencia mayor que "and"
// El resultado de la expresión (true && false) es asignado a $g
// Actúa como: ($g = (true && false))
$g = true && false;
// La constante true es asignada a $h antes de que suceda la operación "and"
// Actúa como: (($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>Operadores para strings</title>
<simpara>
Existen dos operadores para datos tipo <type>string</type>. El primero es el
operador de concatenación ('.'), el cual retorna el resultado de concatenar sus
argumentos derecho e izquierdo. El segundo es el operador de asignación sobre
concatenación ('<literal>.=</literal>'), el cual añade el argumento del lado derecho al
argumento en el lado izquierdo. Por favor consulte <link
linkend="language.operators.assignment">Operadores de
asignación</link> para más información.
</simpara>
<para>
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
$a = "Hello ";
$b = $a . "World!"; // ahora $b contiene "Hello World!"
$a = "Hello ";
$a .= "World!"; // ahora $a contiene "Hello World!"
?>
]]>
</programlisting>
</informalexample>
</para>
<para>
Ver también las secciones del manual sobre el
<link linkend="language.types.string">tipo string</link> y las
<link linkend="ref.strings">funciones de strings</link>.
</para>
</sect1>
<sect1 xml:id="language.operators.array">
<title>Operadores para arrays</title>
<table>
<title>Operadores para arrays</title>
<tgroup cols="3">
<thead>
<row>
<entry>Ejemplo</entry>
<entry>Nombre</entry>
<entry>Resultado</entry>
</row>
</thead>
<tbody>
<row>
<entry>$a + $b</entry>
<entry>Unión</entry>
<entry>Unión de <varname>$a</varname> y <varname>$b</varname>.</entry>
</row>
<row>
<entry>$a == $b</entry>
<entry>Igualdad</entry>
<entry>&true; si <varname>$a</varname> i <varname>$b</varname> tienen las mismas parejas clave/valor.</entry>
</row>
<row>
<entry>$a === $b</entry>
<entry>Identidad</entry>
<entry>&true; si <varname>$a</varname> y <varname>$b</varname> tienen las mismas parejas clave/valor en el mismo
orden y de los mismos tipos.</entry>
</row>
<row>
<entry>$a != $b</entry>
<entry>Desigualdad</entry>
<entry>&true; si <varname>$a</varname> no es igual a <varname>$b</varname>.</entry>
</row>
<row>
<entry>$a &lt;&gt; $b</entry>
<entry>Desigualdad</entry>
<entry>&true; si <varname>$a</varname> no es igual a <varname>$b</varname>.</entry>
</row>
<row>
<entry>$a !== $b</entry>
<entry>No-identidad</entry>
<entry>&true; si <varname>$a</varname> no es idéntica a <varname>$b</varname>.</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
El operador <literal>+</literal> devuelve el array del lado derecho añadido
al array del lado izquierdo; para las claves que existan en ambos arrays, serán utilizados
los elementos del array de la izquierda y serán ignorados los elementos correspondientes del
array de la derecha.
</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; // Unión de $a y $b
echo "Unión de \$a y \$b: \n";
var_dump($c);
$c = $b + $a; // Unión de $b y $a
echo "Unión de \$b y \$a: \n";
var_dump($c);
$a += $b; // Unión de $a += $b es $a y $b
echo "Unión de \$a += \$b: \n";
var_dump($a);
?>
]]>
</programlisting>
</informalexample>
Cuando sea ejecutado, este script producirá la siguiente salida:
<screen role="php">
<![CDATA[
Unión de $a y $b:
array(3) {
["a"]=>
string(5) "apple"
["b"]=>
string(6) "banana"
["c"]=>
string(6) "cherry"
}
Unión de $b y $a:
array(3) {
["a"]=>
string(4) "pear"
["b"]=>
string(10) "strawberry"
["c"]=>
string(6) "cherry"
}
Unión de $a += $b:
array(3) {
'a' =>
string(5) "apple"
'b' =>
string(6) "banana"
'c' =>
string(6) "cherry"
}
]]>
</screen>
</para>
<para>
Los elementos de los arrays son iguales para la comparación si éstos tienen la
misma clave y valor.
</para>
<para>
<example>
<title>Comparando 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>
<para>
Ver también las secciones del manual sobre el
<link linkend="language.types.array">tipo array</link> y
<link linkend="ref.array">funciones de arrays</link>.
</para>
</sect1>
<sect1 xml:id="language.operators.type">
<title>Operadores de tipo</title>
<para>
<literal>instanceof</literal> se utiliza para determinar si una variable de PHP
es un objeto instanciado de una cierta
<link linkend="language.oop5.basic.class">clase</link>:
<example>
<title>Utilizando <literal>instanceof</literal> con clases</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> también se puede utilizar para determinar si una variable
es un objeto instanciado de una clase que hereda de una clase padre:
<example>
<title>Utilizando <literal>instanceof</literal> con clases heredadas</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>
Para comprobar si un objeto <emphasis>no</emphasis> es una instancia de una clase, se
puede usar el <link linkend="language.operators.logical">operador lógico
<literal>not</literal></link>.
<example>
<title>Utilizando <literal>instanceof</literal> para verificar si un objeto <emphasis>no</emphasis> es una
instancia de una clase</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>
Finalmente, <literal>instanceof</literal> también se puede utilizar para determinar si
una variable es un objeto instanciado de una clase que implementa una
<link linkend="language.oop5.interfaces">interface</link>:
<example>
<title>Utilizando <literal>instanceof</literal> para la clase</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>
Aunque <literal>instanceof</literal> se utiliza generalmente con un nombre de clase literal,
también puede ser utilizado con otro objeto o una variable string:
<example>
<title>Utilizando <literal>instanceof</literal> con otras 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 no lanza ningún error si la variable que está siendo comprobada no es
un objeto, simplemente devuelve &false;. Las constantes, sin embargo, no está permitidas.
<example>
<title>Usar <literal>instanceof</literal> para comprobar otras variables</title>
<programlisting role="php">
<![CDATA[
<?php
$a = 1;
$b = NULL;
$c = imagecreate(5, 5);
var_dump($a instanceof stdClass); // $a es un entero
var_dump($b instanceof stdClass); // $b es NULL
var_dump($c instanceof stdClass); // $c es un recurso
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>
Hay algunas trampas a tener en cuenta. Antes de versión de PHP 5.1.0,
<literal>instanceof</literal> llamaría a <function>__autoload</function>
si el nombre de clase no existía. Además, si la clase no estaba cargada,
un error fatal ocurriría. Esto se puede solucionar mediante una referencia
de clase dinámica o una variable string que contenga el nombre de la clase:
<example>
<title>Evitando búsquedas del nombre de clase y errores fatales con <literal>instanceof</literal> en PHP 5.0</title>
<programlisting role="php">
<![CDATA[
<?php
$d = 'NotMyClass';
var_dump($a instanceof $d); // aquí no hay error fatal
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
bool(false)
]]>
</screen>
</example>
</para>
<simpara>
El operador <literal>instanceof</literal> fue introducido en PHP 5.
Antes de esta época se utilizaba <function>is_a</function>, pero
desde entonces <function>is_a</function> se ha quedado obsoleto en favor de
<literal>instanceof</literal>. Tenga en cuenta que a partir de PHP 5.3.0,
<function>is_a</function> ya no está obsoleto.
</simpara>
<para>
Ver también <function>get_class</function> y
<function>is_a</function>.
</para>
</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
-->