Files
archived-doc-pt-br/language/operators/comparison.xml
2025-06-06 22:35:10 -03:00

536 lines
16 KiB
XML

<?xml version="1.0" encoding="utf-8"?><!-- EN-Revision: 16934048f79c6e117cd16a23c09c1b2ea502e284 Maintainer: leonardolara Status: ready --><!-- CREDITS: ae, leonardolara -->
<sect1 xml:id="language.operators.comparison">
<title>Operadores de Comparação</title>
<titleabbrev>Comparação</titleabbrev>
<simpara>
Operadores de comparação, como os seus nomes implicam, permitem que você
compare dois valores. Você pode se interessar em ver
<link linkend="types.comparisons">as tabelas de comparação de tipos</link>,
que tem exemplo das várias comparações entre tipos relacionadas.
</simpara>
<table>
<title>Operadores de comparação</title>
<tgroup cols="3">
<thead>
<row>
<entry>Exemplo</entry>
<entry>Nome</entry>
<entry>Resultado</entry>
</row>
</thead>
<tbody>
<row>
<entry>$a == $b</entry>
<entry>Igual</entry>
<entry>&true; se <varname>$a</varname> é igual a <varname>$b</varname> após equalização de tipos.</entry>
</row>
<row>
<entry>$a === $b</entry>
<entry>Idêntico</entry>
<entry>
&true; se <varname>$a</varname> é igual a <varname>$b</varname>, e eles são do mesmo
tipo.
</entry>
</row>
<row>
<entry>$a != $b</entry>
<entry>Diferente</entry>
<entry>&true; se <varname>$a</varname> não é igual a <varname>$b</varname> depois de equalização de ativos.</entry>
</row>
<row>
<entry>$a &lt;&gt; $b</entry>
<entry>Diferente</entry>
<entry>&true; se <varname>$a</varname> não é igual a <varname>$b</varname> depois de equalização de ativos.</entry>
</row>
<row>
<entry>$a !== $b</entry>
<entry>Não idêntico</entry>
<entry>
&true; se <varname>$a</varname> não é igual a <varname>$b</varname>, ou eles não são do mesmo
tipo.
</entry>
</row>
<row>
<entry>$a &lt; $b</entry>
<entry>Menor que</entry>
<entry>&true; se <varname>$a</varname> é estritamente menor que <varname>$b</varname>.</entry>
</row>
<row>
<entry>$a &gt; $b</entry>
<entry>Maior que</entry>
<entry>&true; se <varname>$a</varname> é estritamente maior que <varname>$b</varname>.</entry>
</row>
<row>
<entry>$a &lt;= $b</entry>
<entry>Menor ou igual</entry>
<entry>&true; se <varname>$a</varname> é menor ou igual a <varname>$b</varname>.</entry>
</row>
<row>
<entry>$a &gt;= $b</entry>
<entry>Maior ou igual</entry>
<entry>&true; se <varname>$a</varname> é maior ou igual a <varname>$b</varname>.</entry>
</row>
<row>
<entry>$a &lt;=&gt; $b</entry>
<entry>Spaceship (nave espacial)</entry>
<entry>
Um <type>int</type> menor que, igual a ou maior que zero quando
<varname>$a</varname> é, respectivamente, menor que, igual a ou maior
que <varname>$b</varname>.
</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
Se ambos os operadores são
<link linkend="language.types.numeric-strings">strings numéricas</link>,
ou um operando é um número e o outro é uma
<link linkend="language.types.numeric-strings">string numérica</link>,
então a comparação é realizada numericamente.
Estas regras se aplicam à instrução
<link linkend="control-structures.switch">switch</link>.
A conversão de tipos não é realizada quando a comparação é realizada através
<literal>===</literal> ou <literal>!==</literal> porque aqui
é realizada a comparação de tipos, além de valores.
</para>
<warning>
<para>
Anteriormente ao PHP 8.0.0, se uma <type>string</type> era comparada a um número
ou uma string numérica, então a <type>string</type> era convertida para
número antes de realizar a comparação. Isto pode levar a resultados
inesperados, como observado no exemplo a seguir:
<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>
<example>
<title>Operadores de Comparação</title>
<programlisting role="php">
<![CDATA[
<?php
// Inteiros
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
// Objetos
$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
// valores e tipos precisam coincidir
$a = (object) ["a" => "b"];
$b = (object) ["b" => "b"];
echo $a <=> $b, ' '; // 1
?>
]]>
</programlisting>
</example>
</para>
<para>
Para vários tipos, comparações são feitas de acordo com a seguinte
tabela (em ordem).
</para>
<table xml:id="language.operators.comparison.types">
<title>Comparação com vários tipos</title>
<tgroup cols="3">
<thead>
<row>
<entry>Tipo do 1º operando</entry>
<entry>Tipo do 2º operando</entry>
<entry>Resultado</entry>
</row>
</thead>
<tbody>
<row>
<entry><type>null</type> ou <type>string</type></entry>
<entry><type>string</type></entry>
<entry>Converte &null; para "", numérico ou comparação léxica</entry>
</row>
<row>
<entry><type>bool</type> ou <type>null</type></entry>
<entry>qualquer</entry>
<entry>Converte para <type>bool</type>, &false; &lt; &true;</entry>
</row>
<row>
<entry><type>object</type></entry>
<entry><type>object</type></entry>
<entry>Classes nativas podem definir suas próprias comparações, classes diferentes
são incomparáveis, same class see <link
linkend="language.oop5.object-comparison">Comparação de Objetos</link>
</entry>
</row>
<row>
<entry><type>string</type>, <type>resource</type>, <type>int</type> ou <type>float</type></entry>
<entry><type>string</type>, <type>resource</type>, <type>int</type> ou <type>float</type></entry>
<entry>Transforma strings e resources para números</entry>
</row>
<row>
<entry><type>array</type></entry>
<entry><type>array</type></entry>
<entry>Array com menos membros é menor, se a chave do operando 1 não é
encontrada no operando 2, então os arrays são incomparáveis, caso contrário compara
valor por valor (veja o seguinte exemplo)</entry>
</row>
<row>
<entry><type>object</type></entry>
<entry>qualquer</entry>
<entry><type>object</type> é sempre maior</entry>
</row>
<row>
<entry><type>array</type></entry>
<entry>qualquer</entry>
<entry><type>array</type> é sempre maior</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
<example>
<title>Comparações de boolean e null</title>
<programlisting role="php">
<![CDATA[
<?php
// bool e null são sempre comparados como booleanos
var_dump(1 == TRUE); // TRUE - o mesmo que (bool) 1 == TRUE
var_dump(0 == FALSE); // TRUE - o mesmo que (bool) 0 == FALSE
var_dump(100 < TRUE); // FALSE - o mesmo que (bool) 100 < TRUE
var_dump(-10 < FALSE);// FALSE - o mesmo que (bool) -10 < FALSE
var_dump(min(-100, -10, NULL, 10, 100)); // NULL - (bool) NULL < (bool) -100 é FALSE < TRUE
?>
]]>
</programlisting>
</example>
</para>
<para>
<example>
<title>Transcrição do padrão de comparação de array</title>
<programlisting role="php" annotations="non-interactive">
<![CDATA[
<?php
// Arrays são comparados assim quando utilizando-se os operadores padrão e operador nave-espacial
function standard_array_compare($op1, $op2)
{
if (count($op1) < count($op2)) {
return -1; // $op1 < $op2
} elseif (count($op1) > count($op2)) {
return 1; // $op1 > $op2
}
foreach ($op1 as $key => $val) {
if (!array_key_exists($key, $op2)) {
return 1;
} elseif ($val < $op2[$key]) {
return -1;
} elseif ($val > $op2[$key]) {
return 1;
}
}
return 0; // $op1 == $op2
}
?>
]]>
</programlisting>
</example>
</para>
<warning>
<title>Comparison of floating point numbers</title>
<para>
Por conta da forma que <type>float</type>s são representados internamente não
se deve testar dois <type>float</type>s com o comparador de igualdade.
</para>
<para>
Veja a documentação de <type>float</type> para mais detalhes.
</para>
</warning>
<note>
<simpara>
Cuidado. A conversão automática de tipos do PHP não é sempre tão óbiva, quando comparando valores de tipos diferentes,
particularmente comparando &integer;s para &boolean;s ou &integer;s para &string;s. No geral é
recomendado utilizar as comparações <literal>===</literal> e <literal>!==</literal> em vez de utilizar
<literal>==</literal> e <literal>!=</literal> na maioria dos casos.
</simpara>
</note>
<sect2 xml:id="language.operators.comparison.incomparable">
<title>Valores não comparáveis</title>
<simpara>
Embora a comparação de identidade (<literal>===</literal> e <literal>!==</literal>)
possa ser aplicada para valores arbitrários, os outros operadores de comparação somente devem
ser aplicados a valores comparáveis. O resultado de comparação de valores não comparáveis
não é definida, e não pode ser garantida.
</simpara>
</sect2>
<sect2 role="seealso">
&reftitle.seealso;
<para>
<simplelist>
<member><function>strcasecmp</function></member>
<member><function>strcmp</function></member>
<member><link linkend="language.operators.array">Array operators</link></member>
<member><link linkend="language.types">Types</link></member>
</simplelist>
</para>
</sect2>
<sect2 xml:id="language.operators.comparison.ternary">
<title>Operador Ternário</title>
<para>
Outro operador condicional é o operador "?:" (ou ternário).
<example>
<title>Atribuindo um valor padrão</title>
<programlisting role="php">
<![CDATA[
<?php
// Example usage for: Ternary Operator
$action = (empty($_POST['action'])) ? 'default' : $_POST['action'];
// O código acima é idêntico a esta instrução if/else
if (empty($_POST['action'])) {
$action = 'default';
} else {
$action = $_POST['action'];
}
?>
]]>
</programlisting>
</example>
A expressão <literal>(expr1) ? (expr2) : (expr3)</literal>
é avaliada para <replaceable>expr2</replaceable> se
<replaceable>expr1</replaceable> é avaliada como &true;, ou
<replaceable>expr3</replaceable> se
<replaceable>expr1</replaceable> é avaliada como &false;.
</para>
<para>
É possível deixar vazia a parte central do operador ternário.
A expressão <literal>expr1 ?: expr3</literal> retorna
o resultado de <replaceable>expr1</replaceable> se <replaceable>expr1</replaceable>
avaliar para &true;, e <replaceable>expr3</replaceable> se não.
<replaceable>expr1</replaceable> somente é avaliada nessa única situação.
</para>
<note>
<simpara>
Note que o operador ternário é uma expressão, e ele não é
avaliado para uma variável, mas para o resultado de uma expressão. Isto é
importante saber se você quer retornar uma variável por referência.
A declaração <literal>return $var == 42 ? $a : $b;</literal> em uma
função que retorna por referência conseqüêntemente não irá funcionar e será
avisado.
</simpara>
</note>
<note>
<para>
É recomendado evitar empilhar operadores ternários.
O comportamento do PHP quando utilizando mais de um operador ternário sem parênteses numa única
expressão é menos óbvia, comparada a outras linguagesn.
Antes do PHP 8.0.0, os operadores ternários eram avaliados com associatividade à esquerda,
em vez de associatividade à direta, como na maioria de outras linguagens.
Depender da associatividade à esquerda foi descontinuado a partir do PHP 7.4.0.
A partir do PHP 8.0.0, o operador ternário é não associativo.
<example>
<title>Comportamento não óbvio do ternário</title>
<programlisting role="php">
<![CDATA[
<?php
// Pode parecer que a expressão a seguir imprime 'true'
echo (true ? 'true' : false ? 't' : 'f');
// No entanto, a saída é na verdade 't' antes do PHP 8.0.0
// Isto ocorre porque operadores ternários são associativos à esquerda
// O seguinte é a versão mais intuitiva do código acima
echo ((true ? 'true' : false) ? 't' : 'f');
// Aqui, é possível ver que a primeira expressão avalia para 'true', e então
// é avalidada para (bool) true, e portanto retorna o variante true da
// segunda expressão ternária
?>
]]>
</programlisting>
</example>
</para>
</note>
<note>
<para>
Encadeamento de ternários curtos (<literal>?:</literal>), é estável, e comporta-se intuitivamente.
Ele avaliará como o primeiro argumento que avalia para uma valor não falso. Observe que valores
não definidos irão emitir um alerta.
<example>
<title>Encadeamento de ternários curtos</title>
<programlisting role="php">
<![CDATA[
<?php
echo 0 ?: 1 ?: 2 ?: 3, PHP_EOL; //1
echo 0 ?: 0 ?: 2 ?: 3, PHP_EOL; //2
echo 0 ?: 0 ?: 0 ?: 3, PHP_EOL; //3
?>
]]>
</programlisting>
</example>
</para>
</note>
</sect2>
<sect2 xml:id="language.operators.comparison.coalesce">
<title>Operador de aglunitação null (Null Coalescing)</title>
<para>
Existe ainda o operador "??" (ou null coalescing).
<example>
<title>Atribuindo um valor padrão</title>
<programlisting role="php">
<![CDATA[
<?php
// Exemplo do operador Null Coalesce
$action = $_POST['action'] ?? 'default';
// O conteúdo acima é idêntico à essa declaração if/else
if (isset($_POST['action'])) {
$action = $_POST['action'];
} else {
$action = 'default';
}
?>
]]>
</programlisting>
</example>
A expressão <literal>(expr1) ?? (expr2)</literal> é avaliada para
<replaceable>expr2</replaceable> se <replaceable>expr1</replaceable> for
&null;, e <replaceable>expr1</replaceable> do contrário.
</para>
<para>
Esse operador em particular não emite aviso caso o valor da esquerda
não exista, assim como <function>isset</function>. Sendo especialmente
útil em chaves de arrays.
</para>
<note>
<simpara>
Note que o operador null coalescing é uma expressão, e ele
não é avaliado para uma variável, mas para o resultado de uma expressão. Isto
é importante saber se você quer retornar uma variável por referência.
A declaração <literal>return $foo ?? $bar;</literal> em uma
função que retorna por referência conseqüêntemente não irá funcionar e será
avisado.
</simpara>
</note>
<note>
<para>
O operador de aglutinação null tem baixa precedência. Isso significa que misturá-lo
com outros operadores (como por exemplo concatenação ou aritmética)
irá provavelmente exigir parênteses.
</para>
<programlisting role="php">
<![CDATA[
<?php
// Emite um aviso que $name não está definido.
print 'Mr. ' . $name ?? 'Anonymous';
// Exibe "Mr. Anonymous"
print 'Mr. ' . ($name ?? 'Anonymous');
?>
]]>
</programlisting>
</note>
<note>
<para>
Note que o operador null coalescing permite a criação de aninhamentos simples:
<example>
<title>Aninhando o operador null coalescing</title>
<programlisting role="php">
<![CDATA[
<?php
$foo = null;
$bar = null;
$baz = 1;
$qux = 2;
echo $foo ?? $bar ?? $baz ?? $qux; // exibe 1
?>
]]>
</programlisting>
</example>
</para>
</note>
</sect2>
</sect1>