PHP, como a maioria de nós sabe, tem digitação fraca . Para quem não sabe, o PHP.net diz:
O PHP não requer (ou suporta) definição explícita de tipo na declaração de variável; o tipo de uma variável é determinado pelo contexto em que a variável é usada.
Ame ou odeie, o PHP relança variáveis on-the-fly. Portanto, o seguinte código é válido:
$var = "10";
$value = 10 + $var;
var_dump($value); // int(20)
O PHP também permite converter explicitamente uma variável, assim:
$var = "10";
$value = 10 + $var;
$value = (string)$value;
var_dump($value); // string(2) "20"
Isso é legal ... mas, para a minha vida, não consigo conceber uma razão prática para fazer isso.
Não tenho problemas com digitação forte em linguagens que o suportam, como Java. Tudo bem, e eu entendo completamente. Além disso, estou ciente - e compreendo perfeitamente a utilidade do - dica de tipo nos parâmetros de função.
O problema que tenho com a conversão de tipos é explicado pela citação acima. Se o PHP puder trocar tipos à vontade , poderá fazê-lo mesmo depois de forçar a conversão de um tipo; e pode fazê-lo on-the-fly quando você precisar de um determinado tipo em uma operação. Isso torna válido o seguinte:
$var = "10";
$value = (int)$var;
$value = $value . ' TaDa!';
var_dump($value); // string(8) "10 TaDa!"
Então qual é o objetivo?
Veja este exemplo teórico de um mundo em que a conversão de tipos definida pelo usuário faz sentido no PHP :
- Você força a variável de conversão
$foo
comoint
→(int)$foo
. - Você tenta armazenar um valor de sequência na variável
$foo
. - PHP lança uma exceção !! ← Isso faria sentido. De repente, existe o motivo da conversão do tipo definido pelo usuário!
O fato de o PHP mudar as coisas conforme necessário torna vago o ponto de conversão do tipo definido pelo usuário. Por exemplo, os dois exemplos de código a seguir são equivalentes:
// example 1
$foo = 0;
$foo = (string)$foo;
$foo = '# of Reasons for the programmer to type cast $foo as a string: ' . $foo;
// example 2
$foo = 0;
$foo = (int)$foo;
$foo = '# of Reasons for the programmer to type cast $foo as a string: ' . $foo;
Um ano depois de fazer essa pergunta, adivinhe quem se viu usando a tipografia em um ambiente prático? Sinceramente.
O requisito era exibir valores monetários em um site para um menu de restaurante. O design do site exigia que os zeros à direita fossem aparados, para que a exibição tivesse a seguinte aparência:
Menu Item 1 .............. $ 4
Menu Item 2 .............. $ 7.5
Menu Item 3 .............. $ 3
A melhor maneira que encontrei para fazer isso foi lançar a variável como um float:
$price = '7.50'; // a string from the database layer.
echo 'Menu Item 2 .............. $ ' . (float)$price;
O PHP apara os zeros à direita do flutuador e, em seguida, o altera novamente como uma string para concatenação.
fonte
(string)
elencos em todos os lugares ?$intval.'bar'
lança uma exceção, eu ainda discordo. Isso não lança uma exceção em nenhum idioma. (Todos os idiomas que eu conheço executam uma conversão automática ou a.toString()
). Se você está dizendo que$intval = $stringval
lança uma exceção, está falando de uma linguagem fortemente tipada. Eu não quis parecer rude, então, desculpe se eu fiz. Eu apenas acho que vai contra o que todo desenvolvedor está acostumado e é muito, muito menos conveniente.Respostas:
Em uma linguagem de tipo fraco, a conversão de tipo existe para remover a ambiguidade nas operações digitadas; caso contrário, o compilador / intérprete usaria ordem ou outras regras para supor qual operação usar.
Normalmente, eu diria que o PHP segue esse padrão, mas nos casos que verifiquei, o PHP se comportou de maneira contra-intuitiva em cada um.
Aqui estão esses casos, usando JavaScript como uma linguagem de comparação.
Concatentação de String
Obviamente, isso não é um problema no PHP porque existem operadores de concatenação de strings (
Javascript.
) e de adição (+
) separados .Comparação de strings
Geralmente, nos sistemas de computadores "5" é maior que "10" porque não o interpreta como um número. Não é assim no PHP, que, mesmo que as duas sejam strings, percebe que são números e remove a necessidade de uma conversão):
Javascript PHPDigitação de assinatura de função
O PHP implementa uma verificação de tipo básica nas assinaturas de funções, mas infelizmente é tão falho que provavelmente provavelmente não pode ser usado.
Eu pensei que poderia estar fazendo algo errado, mas um comentário sobre os documentos confirma que tipos internos diferentes de array não podem ser usados em assinaturas de funções PHP - embora a mensagem de erro seja enganosa.
PHPE, diferente de qualquer outro idioma que eu conheço, mesmo que você use um tipo que ele entenda, null não poderá mais ser passado para esse argumento (
must be an instance of array, null given
). Quão estúpido.Interpretação booleana
[ Editar ]: Este é novo. Pensei em outro caso e, novamente, a lógica é revertida do JavaScript.
Javascript PHPEntão, em conclusão, o único caso útil em que consigo pensar é ... (drumroll)
Tipo de truncamento
Em outras palavras, quando você tem um valor de um tipo (digamos string) e deseja interpretá-lo como outro tipo (int) e deseja forçá-lo a se tornar um dos conjuntos válidos de valores nesse tipo:
Não consigo ver qual upcasting (para um tipo que engloba mais valores) realmente ganharia você.
Então, embora eu discorde do seu uso proposto de digitação (você está propondo essencialmente a digitação estática , mas com a ambiguidade de que somente se fosse lançada à força em um tipo geraria um erro - o que causaria confusão), acho que é uma boa pergunta, porque aparentemente o casting tem muito pouco propósito em PHP.
fonte
E_NOTICE
então? :)E_NOTICE
pode estar ok, mas para mim o estado ambíguo é preocupante - como você saberia olhando um pouco de código se a variável estivesse nesse estado (tendo sido lançada em outro lugar)? Além disso, encontrei outra condição e a adicionei à minha resposta.echo "010" == 010
eecho "0x10" == 0x10
;-)Você está misturando os conceitos de tipo fraco / forte e dinâmico / estático.
O PHP é fraco e dinâmico, mas seu problema é com o conceito de tipo dinâmico. Isso significa que variáveis não têm um tipo, valores têm.
Uma 'conversão de tipo' é uma expressão que produz um novo valor de um tipo diferente do original; não faz nada com a variável (se houver alguma) envolvida.
A única situação em que digito regularmente os valores de conversão está nos parâmetros SQL numéricos. Você deveria higienizar / escapar qualquer valor de entrada inserido nas instruções SQL ou (muito melhor) usar consultas parametrizadas. Mas, se você quiser algum valor que DEVE ser um número inteiro, é muito mais fácil convertê-lo.
Considerar:
se eu deixasse de fora a primeira linha,
$id
seria um vetor fácil para injeção de SQL. O elenco garante que seja um número inteiro inofensivo; qualquer tentativa de inserir algum SQL resultaria simplesmente em uma consulta paraid=0
fonte
mysql_real_escape_string($id);
ainda não soluciona ?mysql_real_escape_string()
tem uma vulnerabilidade de não fazer nada com cadeias de caracteres como '0x01ABCDEF' (ou seja, representação hexadecimal de um número inteiro). Em algumas codificações multibyte (não Unicode por sorte), uma string como essa pode ser usada para interromper a consulta (porque ela é avaliada pelo MySQL como algo que contém uma citação). É por isso quemysql_real_escape_string()
nemis_int()
é a melhor opção para lidar com valores inteiros. Typecasting é.Um uso para a conversão de tipos em PHP que eu encontrei:
estou desenvolvendo um aplicativo Android que faz solicitações HTTP para scripts PHP em um servidor para recuperar dados de um banco de dados. O script armazena dados na forma de um objeto PHP (ou matriz associativa) e é retornado como um objeto JSON para o aplicativo. Sem conversão de tipo, eu receberia algo como isto:
Mas, usando a conversão de tipo PHP
(int)
no ID do usuário ao armazená-lo no objeto PHP, recebo isso de volta ao aplicativo:Então, quando o objeto JSON é analisado no aplicativo, isso evita que eu precise analisar o ID em um número inteiro!
Veja, muito útil.
fonte
Um exemplo é a objectos com um método __toString:
$str = $obj->__toString();
vs$str = (string) $obj;
. Há muito menos digitação no segundo, e o material extra é a pontuação, que leva mais tempo para digitar. Eu também acho que é mais legível, embora outros possam discordar.Outra é fazer uma matriz de elemento único:
array($item);
vs(array) $item;
. Isso colocará qualquer tipo escalar (número inteiro, recurso etc.) dentro de uma matriz.Por outro lado, se
$item
for um objeto, suas propriedades se tornarão chaves para seus valores. No entanto, acho que a conversão de objeto-> matriz é um pouco estranha: propriedades privadas e protegidas fazem parte da matriz e são renomeadas. Para citar a documentação do PHP : variáveis privadas têm o nome da classe anexado ao nome da variável; variáveis protegidas têm um '*' anexado ao nome da variável.Outro uso é a conversão de dados GET / POST em tipos apropriados para um banco de dados. O MySQL pode lidar com isso sozinho, mas acho que os servidores mais compatíveis com ANSI podem rejeitar os dados. A razão de eu apenas mencionar bancos de dados é que, na maioria dos outros casos, os dados terão uma operação executada de acordo com seu tipo em algum momento (ou seja, int / floats geralmente terá cálculos executados neles, etc.).
fonte
int
oufloat
ocorrerá ao criar a consulta).(array) $item
é legal , mas útil?Este script:
funcionará bem para,
script.php?tags[]=one
mas falharáscript.php?tags=one
, porque_GET['tags']
retorna uma matriz no primeiro caso, mas não no segundo. Como o script foi escrito para esperar uma matriz (e você tem menos controle sobre a sequência de consultas enviada ao script), o problema pode ser resolvido lançando adequadamente o resultado de_GET
:fonte
Também pode ser usado como um método rápido e sujo para garantir que dados não confiáveis não quebrem algo, por exemplo, se estiver usando um serviço remoto que possui validação de porcaria e deve aceitar apenas números.
Obviamente, isso é falho e também é tratado implicitamente pelo operador de comparação na instrução if, mas é útil para garantir que você saiba exatamente o que seu código está fazendo.
fonte
$_POST['amount']
contenha uma cadeia de lixo, o php avaliaria que não era maior que zero. Se contivesse uma sequência que representasse um número positivo, avaliaria true.Um "uso" das variáveis de re-conversão do PHP on-the-fly que eu vejo em uso frequentemente é ao recuperar dados de fontes externas (entrada do usuário ou banco de dados). Ele permite que os codificadores (note que eu não disse desenvolvedores) ignorem (ou nem mesmo aprendam) os diferentes tipos de dados disponíveis em diferentes fontes.
Um codificador (observe que eu não disse desenvolvedor) cujo código eu herdei e ainda mantenho não parece saber que existe uma diferença entre a string
"20"
retornada na$_GET
super variável e entre a operação inteira20 + 20
quando ela o adiciona ao o valor no banco de dados. Ela tem sorte que o PHP usa.
para concatenação de strings e não+
como qualquer outra linguagem, porque eu vi o código dela "adicionar" duas strings (umavarcahr
do MySQL e um valor da$_GET
) e obter um int.Este é um exemplo prático? Somente no sentido de permitir que os codificadores se safem sem saber com que tipos de dados estão trabalhando. Eu pessoalmente odeio isso.
fonte