Neden require_once kullanmak kadar kötü?

12 Cevap php

Ben daha iyi bir PHP kodlama uygulamaları hakkında okuduğunuz her şey, çünkü hız require_once kullanmayın söyleyerek tutar.

Neden bu?

require_once olarak aynı şeyi yapmak için uygun / daha iyi bir yolu nedir? Bu konularda, ben PHP5 kullanıyorum.

12 Cevap

Require_once ve include_once sistemi gereklidir / zaten dahil ne bir günlük tutar gerektirir ve başka var her zaman / gerektiren-_once include deyimi, o günlüğünü denetlemek zorunda.

Bir hesaplama temelinde, ben orada bunu yaparken girmeden ekstra çalışma ve kaynakları var, ama bütün app hızını zedelendiğinin kadar görebilir? Ben gerçekten really eski donanım üzerinde konum değil sürece ... şüpheliyim.

Eğer gerçekten bu konuda endişeleriniz varsa, alternatif sen paçayı olduğunca hafif bir şekilde esere kendiniz yapıyor. Basit uygulamalar için, sadece tek bir kez should kafi onu dahil ettik ama yine de hatalar yeniden tanımlamak alıyorsanız eğer, böyle bir şey olabilir emin:

if (!defined('MyIncludeName')) {
    require('MyIncludeName');
    define('MyIncludeName', 1);
}

Bu büyük değil ve kodunuzu kadar önemsiz olacak ama hafif. Şahsen, ben ..._once tablolar çakacağım.

Zaten orada bir "yayınlanmıştır çözüm" olmuştur ve tüm niyet ve amaçlar, yanlış için, var çünkü bu konu, bana yalakalık yapar. En numaralandırmak edelim:

  1. Tanımlar PHP really pahalıdır. You can look it up veya kendiniz test edin, ama PHP bir küresel sabit tanımlama tek etkili yolu bir uzantısı üzerinden. (Sınıf sabitleri aslında oldukça iyi performans akıllıca, ama bu, çünkü 2, bir tartışma noktasıdır)

  2. Eğer kullanıyorsanız require_once() uygun, bu sınıfları dahil olduğunu, hatta bir tanımlamanız gerekmez; eğer sadece kontrol class_exists('Classname'). Eğer dahil dosya kodunu içeriyorsa usul moda kullanıyoruz, yani, require_once() sizin için gerekli olması gerektiğini kesinlikle hiçbir sebep yoktur; Her zaman size bir altprogram çağrısı yapmak için tahmin dosyası içerir.

Bir süre için, bu yüzden bir sürü insan kendi kapanım için class_exists() yöntemini kullandı. Bu fugly çünkü onu sevmiyorum, ama onlar için iyi bir nedeni vardı: require_once() PHP daha yeni sürümleri bazı önce oldukça verimsiz oldu. Ama bu sabit, ve bu koşullu için derlemek olurdu ekstra bytekod ve ekstra yöntem çağrısı, şu ana kadar herhangi bir iç hashtable kontrol overweigh olurdu benim çekişme oldu.

Şimdi, bir itiraf: bu yürütme zaman çok az hesapları, çünkü bu malzeme, test etmek zordur.

Burada hakkında düşünmek gerekir soru: içerir, her zaman tercüman o, geri ayrıştırma moduna geçiş opcodes oluşturmak, ve sonra geri atlamak için var bir tane vurur çünkü genel bir kural olarak, PHP pahalıdır. Eğer 100 + içeren varsa, bu kesinlikle bir performans etkiye sahip olacaktır. Bu opcode cache hayat zor yapar çünkü require_oncenin kullanımından ya da böyle önemli bir soru neden nedenidir. Bir explanation for this bu aşağı kaynar burada ne buldum, ama olmasıdır:

  • Ayrıştırma döneminde, size istek tüm yaşam için gereken dosyaları içerir tam olarak ne biliyorsanız, require() başından ve opcode önbellek o sizin için her şeyi idare edecek.

  • Eğer bir opcode önbellek çalışan değilseniz, zor bir yerdesiniz. (Sadece üretim, geliştirme sırasında bu yapmayın) ve tek bir dosya içine dahil tüm inlining kesinlikle zaman ayrıştırmak yardımcı, ama aynı zamanda yapmak için bir ağrı var ve olabilir, size sırasında dahil olacak tam olarak bilmek gerekir isteği.

  • Özdevinimli_yükle özdevinimli_yükle mantık her zaman çalıştırmak gereken bir bulunur yapılır nedenle, çok uygun, ama yavaş. Uygulamada, ben bir istek için bazı özel dosyaları hakklı bir sorun çok fazla neden olmadığını bulduk, ama size ihtiyacınız olacak tüm dosyaları hakklı edilmemelidir.

  • Belki 10 (bu zarf hesaplama very geri) içerir varsa, tüm bu wanking buna değer değil: sadece veritabanı sorgularını falan optimize.

Merak ettim ve Tech Your Universe Adam Bäckström bağlantısını kontrol etti. Bu makalede, gerekli nedenlerinden biri yerine Require_oncenin kullanılmalıdır açıklanmaktadır. Ancak, iddiaları benim analizine kadar tutun vermedi. Ben çözüm misanalysed olabilir nerede görme ilgi duyarım. Ben karşılaştırmalar için php 5.2.0 kullanılmaktadır.

Başka bir başlık dosyası dahil etmek require_oncenin kullanılan 100 başlık dosyalarını oluşturarak başladı. Bu dosyaların her şey gibi görünüyordu:

<?php
// /home/fbarnes/phpperf/hdr0.php
require_once "../phpperf/common_hdr.php";

?>

Ben hızlı bir bash kesmek kullanarak bu yaratılmış:

for i in /home/fbarnes/phpperf/hdr{00..99}.php; do
  echo "<?php
// $i" > $i
  cat helper.php >> $i;
done

Bu şekilde kolayca require_oncenin kullanarak ve başlık dosyaları da dahil olmak üzere zaman gerektirebilir arasında takas olabilir. Sonra yüz dosyalarını yüklemek için bir app.php yarattı. Bu gibi görünüyordu:

<?php

// Load all of the php hdrs that were created previously
for($i=0; $i < 100; $i++)
{
  require_once "/home/fbarnes/phpperf/hdr$i.php";
}

// Read the /proc file system to get some simple stats
$pid = getmypid();
$fp = fopen("/proc/$pid/stat", "r");
$line = fread($fp, 2048);
$array = split(" ", $line);

// write out the statistics; on RedHat 4.5 w/ kernel 2.6.9
// 14 is user jiffies; 15 is system jiffies
$cntr = 0;
foreach($array as $elem)
{
  $cntr++;
  echo "stat[$cntr]: $elem\n";
}
fclose($fp);

?>

Ben benzeyen bir başlık dosyası kullanılan başlıkları gerektiren ile Require_once başlıkları tezat:

<?php
// /home/fbarnes/phpperf/h/hdr0.php
if(!defined('CommonHdr'))
{
  require "../phpperf/common_hdr.php";
  define('CommonHdr', 1);
}

?>

Require_oncenin vs gerektiren bu çalıştırırken ben çok fark bulamadık. Aslında benim ilk testler Require_once biraz daha hızlı olduğunu ima gibiydi, ama ben mutlaka inanmıyorum. Ben 10000 ile giriş dosyaları deneyi tekrarladı. Burada tutarlı bir fark gördün. Ben testi birden çok kez koştu, sonuç yakın ama require_oncenin kullanarak 30.8 kullanıcı jiffies ve 72.6 sistem jiffies ortalama kullanır; kullanarak 39.4 kullanıcı jiffies ve 72.0 sistem jiffies ortalama kullanım gerektirir. Bu nedenle, yük require_oncenin kullanarak biraz daha düşük olduğu görülmektedir. Ancak, duvar saati hafifçe artar. 10.000 require_once aramalar ortalama tamamlamak için 10.15 saniye kullanımı ve 10.000 aramalar ortalama 9.84 saniye kullanımı gerektirir.

Sonraki adım, bu farklılıkları içine bakmaktır. Ben yapılıyor sistem çağrıları analiz strace'i kullanılır.

Aşağıdaki sisteme Require_once bir dosyayı açmadan önce arama yapılır:

time(NULL)                              = 1223772434
lstat64("/home", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes/phpperf", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes/phpperf/h", {st_mode=S_IFDIR|0755, st_size=270336, ...}) = 0
lstat64("/home/fbarnes/phpperf/h/hdr0.php", {st_mode=S_IFREG|0644, st_size=88, ...}) = 0
time(NULL)                              = 1223772434
open("/home/fbarnes/phpperf/h/hdr0.php", O_RDONLY) = 3

Bu ihtiyaç ile çelişmektedir:

time(NULL)                              = 1223772905
lstat64("/home", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes/phpperf", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes/phpperf/h", {st_mode=S_IFDIR|0755, st_size=270336, ...}) = 0
lstat64("/home/fbarnes/phpperf/h/hdr0.php", {st_mode=S_IFREG|0644, st_size=146, ...}) = 0
time(NULL)                              = 1223772905
open("/home/fbarnes/phpperf/h/hdr0.php", O_RDONLY) = 3

Tech Sizin Universe Require_once daha lstat64 çağrı yapmak gerektiğini ima eder. Ancak, her ikisi lstat64 çağrıların aynı sayıda olun. Muhtemelen, fark yukarıda kodu optimize etmek için APC çalışan değilim olmasıdır. Ancak, ben yaptım sonraki şey, tüm çalışmaları için strace çıktı karşılaştırın oldu:

[fbarnes@myhost phpperf]$ wc -l strace_1000r.out strace_1000ro.out 
  190709 strace_1000r.out
  210707 strace_1000ro.out
  401416 total

Etkili başlık dosyasının başına yaklaşık iki sistem çağrıları require_oncenin kullanarak vardır. Bir fark require_once zaman () işlevi için ek bir arama olmasıdır:

[fbarnes@myhost phpperf]$ grep -c time strace_1000r.out strace_1000ro.out 
strace_1000r.out:20009
strace_1000ro.out:30008

Diğer sistem çağrısı) (getcwd edilir:

[fbarnes@myhost phpperf]$ grep -c getcwd strace_1000r.out strace_1000ro.out 
strace_1000r.out:5
strace_1000ro.out:10004

Ben hdrXXX dosyalarında atıfta göreli yolunu karar verdim çünkü bu denir. Ben bu mutlak bir başvuru yaparsanız, o zaman tek fark ek süre kodunda yapılan (NULL) çağrısıdır:

[fbarnes@myhost phpperf]$ wc -l strace_1000r.out strace_1000ro.out 
  190705 strace_1000r.out
  200705 strace_1000ro.out
  391410 total
[fbarnes@myhost phpperf]$ grep -c time strace_1000r.out strace_1000ro.out
strace_1000r.out:20008
strace_1000ro.out:30008

Bu mutlak yollarını kullanmak yerine göreli yolları sistem aramaların sayısını azaltmak olabilir ima görünüyor. Bunun dışında tek fark (NULL) hızlıdır ne karşılaştırmak için kod instrumenting için kullanılacak göründükleri çağıran zamandır.

Bir diğer not APC optimizasyon paket onu (PHP docs bakınız) Require_once ve include_once çağrılar tarafından yapılan sistem çağrılarının sayısını azalttığını iddia ediyor "apc.include_once_override" adında bir seçenek olmasıdır.

Uzun yazı için özür dilerim. Merak ettim.

Bize bunu önlemek için söylemek bu kodlama uygulamaları için herhangi bir link verebilir misiniz? Bildiğim kadarıyla bana kalırsa, it's a complete non-issue. Ben kaynak kodu kendimi bakmadım, ama include ve include_once arasındaki tek fark include_once Bu dosya bir ekler olduğunu hayal ediyorum dizi ve dizi üzerinde kontrol her zaman. O dizi kriteri tutmak kolay olurdu, bu yüzden üzerinde arama O (log n) olmalı, ve hatta orta-büyücek bir uygulama yalnızca düzine bir çift içerir olurdu.

*_once() fonksiyonları dahil olmak üzere konum dosya zaten dahil oldu biri olarak aynı değildir sağlamak için her ebeveyn dizini tumblr. Bu yavaşlama için neden bir parçasıdır.

Ben kıyaslama için Siege gibi bir araç kullanmanızı öneririz. Tüm önerilen yöntemleri denemek ve yanıt süreleri karşılaştırabilirsiniz.

Daha on require_once() at Tech Your Universe.

(O var) PEAR2 wiki listelemek için kullanılan good reasons for abandoning all ing, at least for library code. These tie you down to rigid directory structures when alternative packaging models like phar ufukta autoload lehine include / gerektirir.

Güncelleme: wiki web arşivlenen sürümü göz gougingly çirkin olduğu gibi, aşağıda en zorlayıcı nedenlerle kopyalanan ettik:

  • include_path is required in order to use a (PEAR) package. This makes it difficult to bundle a PEAR package within another application with its own include_path, to create a single file containing needed classes, to move a PEAR package to a phar archive without extensive source code modification.
  • when top-level require_once is mixed with conditional require_once, this can result in code that is uncacheable by opcode caches such as APC, which will be bundled with PHP 6.
  • relative require_once requires that include_path already be set up to the correct value, making it impossible to use a package without proper include_path

Şeyler yapmak için daha iyi bir yolu, bir nesne yönelimli yaklaşım kullanmak ve kullanmak için __autoload().

Sen, Oli alternatif ve __ autoload () dahil kullanarak, sınamak; ve something like APC yüklü ile test. Ben sürekli irade hız şeyleri kullanarak şüpheliyim.

') (Gerektiren Evet, biraz daha pahalı düz ol daha. Ben size bazı döngüleri kazandıracak gibi, içerir douplicate değil yeterince organize kodunuzu tutabilirsiniz * _once () işlevleri kullanmak istemiyorsanız nokta olduğunu düşünüyorum.

Ama _once () işlevlerini kullanarak app öldürecek değildir. Aslında, sadece don't use it as an excuse to not have to organize your includes. Bazı durumlarda, bunu kullanarak hala kaçınılmaz olduğunu ve büyük bir anlaşma değil.

Ben, ARMUT belgelerinde, require_oncenin gerektiren bir öneri olduğunu düşünüyorum içerir ve include_once. Ben kılavuz takip yapmak. Uygulama daha net olurdu.

Bu hız ile ilgisi yoktur. Bu incelikle başarısız ilgili.

Require_once () başarısız olursa, komut dosyası yapılır. Başka bir şey işlenir. Eğer include_onceyi kullanırsanız () senaryonuzun kalanı vermeye devam için çalışacağız, bu nedenle kullanıcıları potansiyel yok-akıllıca sizin komut başarısız oldu bir şey olacaktır.

Benim kişisel görüşüm sizin için Require_once denetler zaten bu dosyayı dahil ve ölümcül hatalara sonuçlanan çift içerdiği dosyaların hatalarını bastırmak çünkü eğer Require_oncenin kullanımı (veya include_once) kötü uygulama olduğunu (işlevleri / sınıfları / etc yinelenen bildirimi gibi.) .

Eğer bir dosya eklemek için gerekiyorsa bilmeli.