Tudo o que li sobre melhores práticas de codificação PHP continua dizendo que não use require_once
por causa da velocidade.
Por que é isso?
Qual é a melhor / melhor maneira de fazer a mesma coisa require_once
? Se isso importa, estou usando o PHP 5.
php
performance
require-once
Uberfuzzy
fonte
fonte
Respostas:
require_once
einclude_once
ambos exigem que o sistema mantenha um registro do que já foi incluído / necessário. Toda*_once
chamada significa verificar esse log. Definitivamente, há algum trabalho extra sendo feito lá, mas o suficiente para prejudicar a velocidade de todo o aplicativo?... Eu realmente duvido ... Não, a menos que você esteja usando um hardware muito antigo ou faça muito isso .
Se você estiver fazendo milhares
*_once
, poderá fazer o trabalho sozinho de uma maneira mais leve. Para aplicativos simples, apenas certifique-se de incluí-lo apenas uma vez deve ser suficiente, mas se você ainda estiver recebendo erros de redefinição, poderá algo como:Pessoalmente, vou ficar com as
*_once
declarações, mas no benchmark bobo de milhões de passes, você pode ver uma diferença entre os dois:10-100 × mais lento
require_once
e é curioso querequire_once
seja aparentemente mais lentohhvm
. Novamente, isso é relevante apenas para o seu código se você estiver executando*_once
milhares de vezes.fonte
Esse tópico me faz estremecer, porque já existe uma "solução postada" e, para todos os efeitos, está errada. Vamos enumerar:
As definições são realmente caras em PHP. Você pode procurar ou testar você mesmo, mas a única maneira eficiente de definir uma constante global em PHP é através de uma extensão. (As constantes de classe são realmente um desempenho decente, mas esse é um ponto discutível, por causa de 2)
Se você estiver usando
require_once()
adequadamente, ou seja, para inclusão de classes, você nem precisa de uma definição; basta verificar seclass_exists('Classname')
. Se o arquivo que você está incluindo contiver código, ou seja, você o estiver usando de maneira processual, não há absolutamente nenhuma razão querequire_once()
seja necessária para você; sempre que você incluir o arquivo que você presume estar fazendo uma chamada de sub-rotina.Por um tempo, muitas pessoas usaram o
class_exists()
método para suas inclusões. Não gosto porque é fugaz, mas eles tinham bons motivos para:require_once()
era bastante ineficiente antes de algumas das versões mais recentes do PHP. Mas isso foi corrigido, e é meu argumento que o bytecode extra que você precisaria compilar para a condicional e a chamada de método extra, superaria de longe qualquer verificação interna de hashtable.Agora, uma admissão: esse material é difícil de testar, porque é responsável por muito pouco tempo de execução.
Aqui está a pergunta em que você deve estar pensando: inclui, como regra geral, caro no PHP, porque toda vez que o intérprete o atinge, ele deve retornar ao modo de análise, gerar os códigos de operação e voltar. Se você tiver mais de 100 inclusões, isso definitivamente terá um impacto no desempenho. A razão pela qual o uso ou não do require_once é uma pergunta tão importante é porque dificulta a vida dos caches de código de operação. Uma explicação para isso pode ser encontrada aqui, mas o que isso se resume é o seguinte:
Se durante o tempo de análise, você souber exatamente o que inclui os arquivos necessários para toda a vida útil da solicitação,
require()
aqueles no início e o cache do opcode tratará de tudo o mais para você.Se você não está executando um cache de código de operação, está em uma situação difícil. A inclusão de todas as suas inclusões em um arquivo (não faça isso durante o desenvolvimento, apenas na produção) certamente pode ajudar a analisar o tempo, mas é uma tarefa difícil de fazer e você também precisa saber exatamente o que incluirá durante o processo. solicitação.
O carregamento automático é muito conveniente, mas lento, porque a lógica do carregamento automático precisa ser executada toda vez que uma inclusão é feita. Na prática, descobri que o carregamento automático de vários arquivos especializados para uma solicitação não causa muitos problemas, mas você não deve carregar automaticamente todos os arquivos necessários.
Se você tiver talvez 10 inclusões (este é um cálculo muito posterior ao envelope), toda essa punheta não vale a pena: apenas otimize suas consultas ao banco de dados ou algo assim.
fonte
define()
,require_once()
edefined()
todos levam cerca de 1 a 2 microssegundos cada na minha máquina.Fiquei curioso e verifiquei o link de Adam Backstrom para Tech Your Universe . Este artigo descreve um dos motivos que exigem que deve ser usado em vez de require_once. No entanto, suas reivindicações não se sustentaram na minha análise. Eu estaria interessado em ver onde eu posso ter analisado mal a solução. Eu usei o PHP 5.2.0 para comparações.
Comecei criando 100 arquivos de cabeçalho que usavam require_once para incluir outro arquivo de cabeçalho. Cada um desses arquivos se parecia com:
Eu os criei usando um hack rápido do Bash:
Dessa forma, eu poderia facilmente trocar entre usar require_once e exigir ao incluir os arquivos de cabeçalho. Eu criei um app.php para carregar os cem arquivos. Parecia:
Comparei os cabeçalhos require_once com os headers require que usavam um arquivo de cabeçalho parecido com:
Não encontrei muita diferença ao executar isso com require vs. require_once. De fato, meus testes iniciais pareciam sugerir que require_once era um pouco mais rápido, mas eu não acredito necessariamente nisso. Repeti o experimento com 10000 arquivos de entrada. Aqui eu vi uma diferença consistente. Eu executei o teste várias vezes, os resultados estão próximos, mas usando require_once usa, em média, 30,8 jiffies do usuário e 72,6 jiffies do sistema; o uso requer usos em média de 39,4 instantes do usuário e 72,0 instantes do sistema. Portanto, parece que a carga é um pouco menor usando require_once. No entanto, o tempo do relógio de parede é ligeiramente aumentado. As 10.000 chamadas require_once usam 10,15 segundos para concluir, em média, e 10.000 exigem chamadas usam 9,84 segundos, em média.
O próximo passo é analisar essas diferenças. Eu usei o strace para analisar as chamadas do sistema que estão sendo feitas.
Antes de abrir um arquivo a partir de require_once, são feitas as seguintes chamadas do sistema:
Isso contrasta com exige:
Tech Your Universe implica que require_once deve fazer mais chamadas lstat64. No entanto, ambos fazem o mesmo número de chamadas lstat64. Possivelmente, a diferença é que não estou executando o APC para otimizar o código acima. No entanto, a seguir, comparei a saída do strace para todas as execuções:
Efetivamente, existem aproximadamente mais duas chamadas do sistema por arquivo de cabeçalho ao usar require_once. Uma diferença é que require_once possui uma chamada adicional para a função time ():
A outra chamada do sistema é getcwd ():
Isso é chamado porque eu decidi o caminho relativo mencionado nos arquivos hdrXXX. Se eu fizer disso uma referência absoluta, a única diferença é a chamada de tempo adicional (NULL) feita no código:
Isso parece implicar que você pode reduzir o número de chamadas do sistema usando caminhos absolutos em vez de caminhos relativos. A única diferença fora disso são as chamadas de tempo (NULL) que parecem ser usadas para instrumentar o código para comparar o que é mais rápido.
Outra observação é que o pacote de otimização da APC tem uma opção chamada "apc.include_once_override", que afirma que reduz o número de chamadas do sistema feitas pelas chamadas require_once e include_once (consulte a documentação do PHP ).
fonte
Você pode nos fornecer links para essas práticas de codificação que dizem para evitá-lo? Para mim, é um não-problema completo . Eu mesmo não olhei o código-fonte, mas imagino que a única diferença entre
include
einclude_once
é queinclude_once
adicione esse nome de arquivo a uma matriz e verifique a matriz toda vez. Seria fácil manter essa matriz classificada, portanto, a pesquisa nela deveria ser O (log n), e mesmo um aplicativo de tamanho médio teria apenas algumas dezenas de inclusões.fonte
Uma maneira melhor de fazer as coisas é usar uma abordagem orientada a objetos e usar __autoload () .
fonte
__autoload()
é desencorajado e pode ser preterido no futuro, você deve usarspl_autoload_register(...)
esses dias ... PS2: não me interpretem mal, às vezes uso a funcionalidade de carregamento automático; )Não está usando a função que é ruim. É um entendimento incorreto de como e quando usá-lo, em uma base geral de códigos. Vou apenas adicionar um pouco mais de contexto a essa noção possivelmente incompreendida:
As pessoas não devem pensar que require_once é uma função lenta. Você precisa incluir seu código de uma maneira ou de outra. A velocidade de
require_once()
vs.require()
não é o problema. Trata-se das advertências que dificultam o desempenho que podem resultar em usá-lo às cegas. Se usado amplamente sem considerar o contexto, pode levar a um enorme desperdício de memória ou código desnecessário.O que eu vi realmente ruim é quando grandes estruturas monolíticas são usadas
require_once()
de todas as maneiras erradas, especialmente em um ambiente complexo orientado a objetos (OO).Veja o exemplo do uso
require_once()
na parte superior de todas as classes, como visto em muitas bibliotecas:Portanto, a
User
classe foi projetada para usar as três outras classes. Justo!Mas agora, e se um visitante estiver navegando no site e nem mesmo estiver conectado e a estrutura carregar:
require_once("includes/user.php");
para cada solicitação única.Inclui 1 + 3 classes desnecessárias que nunca serão usadas durante essa solicitação específica. É assim que as estruturas inchadas acabam usando 40 MB por solicitação, em vez de 5 MB ou menos.
As outras maneiras pelas quais isso pode ser mal utilizado é quando uma classe é reutilizada por muitas outras! Digamos que você tenha cerca de 50 classes que usam
helper
funções. Para garantir quehelpers
estejam disponíveis para essas classes quando elas forem carregadas, você obtém:Não há nada errado aqui por si só. No entanto, se uma solicitação de página incluir 15 classes semelhantes. Você está executando
require_once
15 vezes ou para um visual agradável:O uso de require_once () tecnicamente afeta o desempenho para executar essa função 14 vezes, além de precisar analisar essas linhas desnecessárias. Com apenas 10 outras classes altamente usadas com esse problema semelhante, ele poderia representar mais de 100 linhas desse código repetitivo bastante inútil.
Com isso, provavelmente vale a pena usar
require("includes/helpers.php");
na inicialização do seu aplicativo ou estrutura. Mas como tudo é relativo, tudo depende se o peso versus a frequência de uso dahelpers
classe vale a pena salvar de 15 a 100 linhas derequire_once()
. Mas se a probabilidade de não usar ohelpers
arquivo em uma solicitação específica for nenhuma, então vocêrequire
deve estar na sua classe principal. Terrequire_once
cada aula separadamente torna-se um desperdício de recursos.A
require_once
função é útil quando necessário, mas não deve ser considerada uma solução monolítica a ser usada em qualquer lugar para carregar todas as classes.fonte
O wiki do PEAR2 (quando existia) costumava listar boas razões para abandonar todas as diretrizes de inclusão / inclusão em favor do carregamento automático , pelo menos para o código da biblioteca. Isso o vincula a estruturas de diretório rígidas quando modelos de embalagem alternativos, como o phar, estão no horizonte.
Atualização: Como a versão arquivada na Web do wiki é extremamente feia, copiei os motivos mais convincentes abaixo:
fonte
As
*_once()
funções stat cada diretório pai para garantir que o arquivo que você está incluindo não seja o mesmo que já foi incluído. Isso faz parte do motivo da desaceleração.Eu recomendo o uso de uma ferramenta como o Siege para benchmarking. Você pode tentar todas as metodologias sugeridas e comparar os tempos de resposta.
Mais informações
require_once()
estão no Tech Your Universe .fonte
Mesmo que
require_once
einclude_once
sejam mais lentos do querequire
einclude
(ou quaisquer alternativas que possam existir), estamos falando do menor nível de micro-otimização aqui. Você gasta muito mais tempo otimizando esse loop ou consulta de banco de dados mal escrito do que se preocupando com algo assimrequire_once
.Agora, alguém poderia argumentar dizendo que
require_once
permite práticas de codificação ruins, porque você não precisa prestar atenção para manter suas inclusões limpas e organizadas, mas isso não tem nada a ver com a função em si e principalmente com a velocidade.Obviamente, o carregamento automático é melhor em prol da limpeza do código e da facilidade de manutenção, mas quero deixar claro que isso não tem nada a ver com velocidade .
fonte
Você testa, usando include, a alternativa de oli e __autoload (); e teste-o com algo como o APC instalado.
Duvido que o uso constante acelere as coisas.
fonte
Sim, é um pouco mais caro do que o simples requerido (). Eu acho que o ponto é se você pode manter seu código organizado o suficiente para não duplicar as inclusões, não use as funções * _once (), pois isso poupará alguns ciclos.
Mas o uso das funções _once () não matará seu aplicativo. Basicamente, não use isso como desculpa para não ter que organizar suas inclusões . Em alguns casos, usá-lo ainda é inevitável, e não é grande coisa.
fonte
Eu acho que na documentação do PEAR, há uma recomendação para require, require_once, include e include_once. Eu sigo essa orientação. Sua aplicação seria mais clara.
fonte
Não tem nada a ver com velocidade. É sobre falhar graciosamente.
Se require_once () falhar, seu script estará pronto. Nada mais é processado. Se você usar o include_once (), o restante do seu script tentará continuar renderizando, para que seus usuários não sejam os mais sensatos a algo que falhou no seu script.
fonte
Minha opinião pessoal é que o uso de require_once (ou include_once) é uma prática ruim, porque require_once verifica se você já incluiu esse arquivo e suprime erros de arquivos incluídos duplos, resultando em erros fatais (como declaração duplicada de funções / classes / etc.) .
Você deve saber se precisa incluir um arquivo.
fonte