Eu tenho vários aplicativos mais antigos que lançam muitas mensagens "xyz is undefined" e "undefined offset" quando executados no nível de erro E_NOTICE, porque a existência de variáveis não é explicitamente verificada usando isset()
e consorts.
Estou pensando em trabalhar com eles para torná-los compatíveis com E_NOTICE, já que avisos sobre variáveis ausentes ou deslocamentos podem ser salva-vidas, pode haver algumas pequenas melhorias de desempenho a serem obtidas e, em geral, é a maneira mais limpa.
No entanto, eu não gosto do que infligir centenas de isset()
empty()
e array_key_exists()
s faz com o meu código. Ele fica inchado, fica menos legível, sem ganhar nada em termos de valor ou significado.
Como posso estruturar meu código sem um excesso de verificações de variáveis e, ao mesmo tempo, ser compatível com E_NOTICE?
fonte
Respostas:
Para os interessados, expandi este tópico em um pequeno artigo, que fornece as informações abaixo em uma forma um pouco melhor estruturada: O guia definitivo para isset do PHP e vazio
IMHO você deve pensar não apenas em tornar o aplicativo "compatível com E_NOTICE", mas em reestruturar tudo. Ter centenas de pontos em seu código que tentam regularmente usar variáveis inexistentes soa como um programa mal estruturado. Tentar acessar variáveis inexistentes nunca deveria acontecer, outras linguagens se recusam a isso em tempo de compilação. O fato de o PHP permitir que você faça isso não significa que você deva.
Esses avisos existem para ajudá- lo, não para incomodá-lo. Se você receber um aviso "Você está tentando trabalhar com algo que não existe!" , sua reação deve ser "Ops, que pena, deixe-me corrigir isso o mais rápido possível." De que outra forma você vai dizer a diferença entre "variáveis que funcionam muito bem indefinidas" e código honestamente errado que pode levar a erros graves ? Esta é também a razão pela qual você sempre, sempre , desenvolve com relatórios de erros voltados para 11 e continua plugando em seu código até que nenhum
NOTICE
é emitido. Desativar o relatório de erros é apenas para ambientes de produção, para evitar vazamento de informações e fornecer uma melhor experiência do usuário, mesmo em caso de código com erros.Para elaborar:
Você sempre precisará
isset
ouempty
em algum lugar em seu código, a única maneira de reduzir sua ocorrência é inicializar suas variáveis corretamente. Dependendo da situação, existem diferentes maneiras de fazer isso:Argumentos da função:
Não há necessidade de verificar se
$bar
ou$baz
estão definidos dentro da função porque você acabou de defini-los. Tudo o que você precisa se preocupar é se o valor deles é avaliado comotrue
oufalse
(ou qualquer outra coisa).Variáveis regulares em qualquer lugar:
Inicialize suas variáveis no topo de um bloco de código no qual você irá usá-las. Isso resolve o
!isset
problema, garante que suas variáveis sempre tenham um valor padrão conhecido, dá ao leitor uma ideia de como o código a seguir funcionará e, portanto, também serve como uma espécie de autodocumentação.Matrizes:
Da mesma forma que acima, você está inicializando o array com os valores padrão e os substituindo pelos valores reais.
Nos casos restantes, digamos um modelo em que você está gerando valores que podem ou não ser definidos por um controlador, você apenas terá que verificar:
Se você está usando regularmente
array_key_exists
, deve avaliar para que está usando. A única vez que faz diferença é aqui:Porém, conforme declarado acima, se você estiver inicializando corretamente suas variáveis, não precisa verificar se a chave existe ou não, porque você sabe que existe. Se você está recebendo a matriz a partir de uma fonte externa, o valor mais provável não será
null
, mas''
,0
,'0'
,false
ou algo parecido, valor ou seja, um você pode avaliar comisset
ouempty
, dependendo da sua intenção. Se você definir regularmente uma chave de array paranull
e quiser que signifique qualquer coisa menosfalse
, ou seja, se no exemplo acima os resultados divergentesisset
earray_key_exists
fizerem diferença para a lógica do seu programa, você deve se perguntar por quê. A mera existência de uma variável não deve ser importante, apenas seu valor deve ser relevante. Se a chave for um sinalizadortrue
/false
, usetrue
oufalse
nãonull
. A única exceção a isso seriam bibliotecas de terceiros que queremnull
significar alguma coisa, mas comonull
é tão difícil de detectar no PHP, ainda não encontrei nenhuma biblioteca que faça isso.fonte
if ($array["xyz"])
vez deisset()
ouarray_key_exists()
que considero legítimas, certamente não são problemas estruturais (corrija-me se estiver enganado). Adicionararray_key_exists()
parece um desperdício terrível para mim.array_key_exists
vez de um simplesisset($array['key'])
ou!empty($array['key'])
. Claro, ambos adicionam 7 ou 8 caracteres ao seu código, mas eu dificilmente consideraria isso um problema. Também ajuda a esclarecer seu código:if (isset($array['key']))
significa que essa variável é realmente opcional e pode estar ausente, enquantoif ($array['key'])
significa apenas "se verdadeiro". Se você receber um aviso para o último, sabe que sua lógica está ferrada em algum lugar.Basta escrever uma função para isso. Algo como:
que você pode usar como
Faça o mesmo para coisas triviais como
get_number()
,get_boolean()
,get_array()
e assim por diante.fonte
<input name="something[]" />
. Isso causaria um erro (já que o corte não pode ser aplicado a matrizes) usando o código acima, neste caso, deve-se usaris_string
e, possivelmentestrval
. Este não é simplesmente um caso em que se deve usarget_array
uma vez que a entrada do usuário (malicioso) talvez qualquer coisa e o analisador de entrada do usuário nunca deve gerar erro de qualquer maneira.Eu acredito que uma das melhores maneiras de lidar com esse problema é acessando valores de matrizes GET e POST (COOKIE, SESSION, etc.) por meio de uma classe.
Crie uma classe para cada uma dessas matrizes e declare os métodos
__get
e__set
( sobrecarga ).__get
aceita um argumento que será o nome de um valor. Este método deve verificar este valor na matriz global correspondente, usandoisset()
ouempty()
e retornar o valor se existir ounull
(ou algum outro valor padrão) caso contrário.Depois disso, você pode acessar com segurança os valores do array desta maneira:
$POST->username
e fazer qualquer validação, se necessário, sem usarisset()
s ouempty()
s. Seusername
não existir na matriz global correspondente,null
será retornado, portanto, nenhum aviso ou notificação será gerado.fonte
Não me importo de usar a
array_key_exists()
função. Na verdade, eu prefiro usar essa função específica em vez de depender de funções dehack, que podem mudar seu comportamento no futuro,como(eliminado para evitar suscetibilidades ).empty
eisset
No entanto, uso uma função simples que é útil nisso e em algumas outras situações ao lidar com índices de array :
Digamos que você tenha as seguintes matrizes:
Como você obtém o "valor" dos arrays? Simples:
Já temos matrizes uni e multidimensionais cobertas, o que mais podemos fazer?
Pegue o seguinte trecho de código, por exemplo:
Muito chato, não é? Aqui está outra abordagem usando a
Value()
função:Como exemplo adicional, use a
RealIP()
função para um teste:Legal, hein? ;)
fonte
isset
eempty
são construções de linguagem , não funções. Em segundo lugar, se quaisquer funções / construções de linguagem da biblioteca central mudarem seu comportamento, você pode ou não estar ferrado. E searray_key_exists
mudar seu comportamento? A resposta é que não, contanto que você esteja usando conforme documentado. Eisset
está documentado para ser usado exatamente assim. As funções de pior caso são preteridas em uma ou duas versões principais. A síndrome NIH é ruim!array_key_exists()
para verificar se existe uma chave em um array ?!array_key_exists()
foi criado exatamente para isso , prefiro confiar nele para esse fim do queisset()
e principalmenteempty()
cuja descrição oficial é: "determinar se uma variável está vazia", não menciona nada se realmente existe. Seu comentário e voto negativo é um dos mais ridículos que testemunhei durante todo o mês .isset
eempty
não são nem mais nem menos confiáveis do quearray_key_exists
e podem fazer exatamente o mesmo trabalho. Seu segundo exemplo extenso pode ser escrito$domain = isset($domain['host']) ? $domain['host'] : 'N/A';
apenas com os recursos básicos da linguagem, sem chamadas de funções extras ou declarações necessárias (observe que eu não defendo necessariamente o uso do operador ternário; o)). Para variáveis escalares comuns, você ainda precisará usarisset
ouempty
e poderá usá-los para matrizes exatamente da mesma maneira. "Confiabilidade" é um mau motivo para não fazê-lo.Eu estou aqui com você. Mas os designers de PHP cometeram erros muito mais graves do que isso. Além de definir uma função personalizada para qualquer leitura de valor, não há como contornar isso.
fonte
params["width"] = params["width"] || 5
para definir padrões em vez de toda aquela bobagem comisset()
chamadas.register_globals
emagic_quotes
. Os problemas que isso fomentam tornam as variáveis não inicializadas quase inofensivas em comparação.Eu uso essas funções
Exemplos
fonte
Bem-vindo ao operador de coalescência nulo (PHP> = 7.0.1):
PHP diz:
fonte
Faça uma função que retorna
false
se não for definida e, se especificada,false
se estiver vazia. Se válido, ele retorna a variável. Você pode adicionar mais opções como visto no código abaixo:fonte
O software não funciona magicamente pela graça de Deus. Se você está esperando algo que está faltando, é necessário lidar com isso da maneira adequada.
Se você ignorá-lo, provavelmente estará criando brechas de segurança em seus aplicativos. Em linguagens estáticas, acessar uma variável não definida simplesmente não é possível. Ele não irá simplesmente compilar ou travar seu aplicativo se ele for nulo.
Além disso, torna seu aplicativo impossível de manter e você vai ficar louco quando coisas inesperadas acontecerem. O rigor da linguagem é uma obrigação e o PHP, por design, está errado em muitos aspectos. Isso o tornará um péssimo programador se você não souber.
fonte
Não tenho certeza de qual é a sua definição de legibilidade, mas o uso adequado dos blocos empty (), isset () e try / throw / catch é muito importante para todo o processo.
Se seu E_NOTICE está vindo de $ _GET ou $ _POST, então eles devem ser verificados em relação a empty () junto com todas as outras verificações de segurança que esses dados devem passar.
Se estiver vindo de feeds externos ou bibliotecas, deve ser agrupado em try / catch.
Se estiver vindo do banco de dados, $ db_num_rows () ou seu equivalente deve ser verificado.
Se vier de variáveis internas, elas devem ser inicializadas corretamente. Freqüentemente, esses tipos de avisos vêm da atribuição de uma nova variável ao retorno de uma função que retorna FALSE em uma falha. Eles devem ser incluídos em um teste que, no caso de uma falha, pode atribuir à variável um valor padrão aceitável que o código pode manipular ou lançar uma exceção que o código pode manipular.
Essas coisas tornam o código mais longo, adicionam blocos extras e adicionam testes extras, mas eu discordo de você porque acho que definitivamente adicionam valor extra.
fonte
Que tal usar a
@
operadora?Por exemplo:
Você pode dizer que isso é ruim porque você não tem controle do que acontece "dentro" de $ foo (se for uma chamada de função que contém um erro de PHP, por exemplo), mas se você usar essa técnica apenas para variáveis, isso é equivalente a:
fonte
if(isset($foo))
é o suficiente, na verdade. Ele retornaráTRUE
se a expressão for avaliada comoTRUE
.