回答:
require_once
そしてinclude_once
、両方のシステムがすでに含まれているもの/必要なのログを保持する必要があります。すべての*_once
呼び出しは、そのログをチェックすることを意味します。では、いくつかの余分な作業が確実に行われていますが、アプリ全体の速度を損なうのに十分ですか?
...私はそれを本当に疑います...あなたが本当に古いハードウェアを使っているか、それをたくさんやっていない限り、そうではありません。
あなたがいる場合している何千ものをやって*_once
、あなたは軽量な方法で作業を自分で行うことができます。単純なアプリの場合、1回だけ含めたことを確認するだけで十分ですが、それでも再定義エラーが発生する場合は、次のようにすることができます。
if (!defined('MyIncludeName')) {
require('MyIncludeName');
define('MyIncludeName', 1);
}
私は個人的に*_once
ステートメントに固執しますが、愚かなミリオンパスのベンチマークでは、2つの間の違いを見ることができます:
php hhvm
if defined 0.18587779998779 0.046600103378296
require_once 1.2219581604004 3.2908599376678
で10〜100倍遅くなりrequire_once
、require_once
で一見遅くなるのは不思議ですhhvm
。繰り返しますが、これは、*_once
何千回も実行している場合にのみコードに関連します。
<?php // test.php
$LIMIT = 1000000;
$start = microtime(true);
for ($i=0; $i<$LIMIT; $i++)
if (!defined('include.php')) {
require('include.php');
define('include.php', 1);
}
$mid = microtime(true);
for ($i=0; $i<$LIMIT; $i++)
require_once('include.php');
$end = microtime(true);
printf("if defined\t%s\nrequire_once\t%s\n", $mid-$start, $end-$mid);
<?php // include.php
// do nothing.
「投稿されたソリューション」がすでにあり、すべての意図と目的のために間違っているため、このスレッドは私を不快にさせます。列挙してみましょう:
PHPでは、定義は非常に高価です。自分で調べたり、テストしたりできますが、PHPでグローバル定数を定義する唯一の効率的な方法は、拡張機能を使用することです。(クラス定数は実際にはかなり賢明なパフォーマンスですが、これは2のため、議論の余地があります)
require_once()
適切に使用している場合、つまりクラスを含める場合は、定義する必要さえありません。だけを確認してくださいclass_exists('Classname')
。インクルードするファイルにコードが含まれている場合、つまり、手順に従ってファイルを使用している場合、require_once()
必要な理由はまったくありません。ファイルをインクルードするたびに、サブルーチン呼び出しを行っていると想定します。
したがって、しばらくの間、多くの人々がこのclass_exists()
方法をインクルージョンに使用していました。あいまいであるので、私はそれが好きではありませんがrequire_once()
、PHPのより最近のバージョンの前にはかなり非効率的であったという正当な理由がありました。しかし、それは修正されており、条件付きでコンパイルする必要がある追加のバイトコード、および追加のメソッド呼び出しは、内部のハッシュテーブルのチェックをはるかに上回ってしまうというのが私の主張です。
さて、入場料:実行時間のほとんどを占めていないため、これはテストするのが難しいです。
考慮すべき問題は次のとおりです。インクルーダーがヒットするたびに、インタープリターが解析モードに戻り、オペコードを生成してからジャンプする必要があるため、PHPには一般的にインクルードが高価です。100以上のインクルードがある場合、これは間違いなくパフォーマンスに影響します。require_onceを使用するか使用しないかが非常に重要である理由は、オペコードキャッシュの運用を困難にするためです。これの説明はここにありますが、要約すると次のとおりです。
解析時に、リクエストの存続期間全体で必要なインクルードファイルが正確にわかっている場合は、require()
最初のファイルとopcodeキャッシュが他のすべてを処理します。
オペコードキャッシュを実行していない場合は、難しい場所にいます。すべてのインクルードを1つのファイルにインライン化すると(開発中にこれを行わず、本番環境のみで)、時間の解析に役立ちますが、これは面倒です。また、リクエスト。
オートロードは非常に便利ですが、インクルードが行われるたびにオートロードロジックを実行する必要があるため、処理が遅くなります。実際には、1つの要求に対していくつかの特殊なファイルをオートロードしても問題はそれほど多くないことがわかりましたが、必要なすべてのファイルをオートロードするべきではありません。
おそらく10個のインクルードがある場合(これはエンベロープ計算の非常に後ろです)、データベースのクエリなどを最適化するだけで、このすばらしさには価値がありません。
define()
、require_once()
そしてdefined()
私のマシンで1-2マイクロそれぞれについてのすべてのテイク。
気になったので、Adam BackstromのTech Your Universeへのリンクを調べました。この記事では、require_onceの代わりにrequireを使用する必要がある理由の1つについて説明します。しかし、彼らの主張は私の分析には及ばなかった。ソリューションを誤って分析した可能性のある場所を確認することに興味があります。比較にはPHP 5.2.0を使用しました。
require_onceを使用して別のヘッダーファイルを含める100個のヘッダーファイルを作成することから始めました。これらのファイルはそれぞれ次のようなものでした。
<?php
// /home/fbarnes/phpperf/hdr0.php
require_once "../phpperf/common_hdr.php";
?>
私は簡単なBashハックを使用してこれらを作成しました:
for i in /home/fbarnes/phpperf/hdr{00..99}.php; do
echo "<?php
// $i" > $i
cat helper.php >> $i;
done
このようにして、ヘッダーファイルを含めるときにrequire_onceとrequireの使用を簡単に切り替えることができます。次に、100個のファイルをロードするapp.phpを作成しました。これは次のようになりました。
<?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 with 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);
?>
require_onceヘッダーと、次のようなヘッダーファイルを使用するrequireヘッダーを対比しました。
<?php
// /home/fbarnes/phpperf/h/hdr0.php
if(!defined('CommonHdr'))
{
require "../phpperf/common_hdr.php";
define('CommonHdr', 1);
}
?>
requireとrequire_onceを使用してこれを実行しても、それほど大きな違いは見つかりませんでした。実際、最初のテストではrequire_onceの方がわずかに速いことを示唆していたようですが、必ずしもそうであるとは限りません。10000の入力ファイルで実験を繰り返しました。ここで私は一貫した違いを見ました。私はテストを複数回実行しましたが、結果は近いですが、require_onceを使用すると、平均で30.8ユーザーjiffと72.6システムjiffが使用されます。requireは、平均で39.4ユーザーjiffと72.0システムjiffを使用します。したがって、require_onceを使用すると、負荷がわずかに低くなるようです。ただし、実時間はわずかに増加します。10,000のrequire_onceコールは平均で10.15秒を使用して完了し、10,000のrequireコールは平均で9.84秒を使用します。
次のステップは、これらの違いを調べることです。straceを使用して、行われているシステムコールを分析しました。
require_onceからファイルを開く前に、次のシステムコールが行われます。
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
これはrequireとは対照的です:
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 Your Universeは、require_onceがより多くのlstat64呼び出しを行う必要があることを示唆しています。ただし、どちらも同じ数のlstat64呼び出しを行います。おそらく、上のコードを最適化するためにAPCを実行していないという違いがあります。ただし、次に、実行全体のstraceの出力を比較しました。
[fbarnes@myhost phpperf]$ wc -l strace_1000r.out strace_1000ro.out
190709 strace_1000r.out
210707 strace_1000ro.out
401416 total
require_onceを使用すると、実質的にヘッダーファイルごとに約2つのシステムコールが追加されます。違いの1つは、require_onceがtime()関数をさらに呼び出すことです。
[fbarnes@myhost phpperf]$ grep -c time strace_1000r.out strace_1000ro.out
strace_1000r.out:20009
strace_1000ro.out:30008
他のシステムコールはgetcwd()です。
[fbarnes@myhost phpperf]$ grep -c getcwd strace_1000r.out strace_1000ro.out
strace_1000r.out:5
strace_1000ro.out:10004
これは、hdrXXXファイルで参照される相対パスに決定したために呼び出されます。これを絶対参照にすると、唯一の違いは、コードで追加のtime(NULL)呼び出しが行われることです。
[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
これは、相対パスではなく絶対パスを使用してシステムコールの数を減らすことができることを意味しているようです。それ以外の唯一の違いは、何が速いかを比較するコードをインストルメント化するために使用されるように見えるtime(NULL)呼び出しです。
もう1つの注意点は、APC最適化パッケージに「apc.include_once_override」と呼ばれるオプションがあり、require_onceおよびinclude_once呼び出しによって行われるシステムコールの数が減ると主張していることです(PHPのドキュメントを参照)。
それを避けるように言うこれらのコーディング慣行へのリンクを教えていただけますか?私に関する限り、これは完全な問題ではありません。私は、ソースコードを自分自身を見ていないが、私は間の唯一の違いを想像するinclude
と、include_once
つまりinclude_once
、配列の各時間の経過アレイと小切手にそのファイル名を追加します。その配列を並べ替えておくのは簡単です。そのため、その配列を検索するとO(log n)になるはずです。
物事を行うためのより良い方法は、オブジェクト指向のアプローチを使用して__autoload()を使用することです。
__autoload()
推奨され、それが将来的に廃止されることがあり、あなたが使用する必要がありますspl_autoload_register(...)
これらの日... PS2:誤解しないでください、私は時々使用の自動ロード機能を実行します。 )
悪い機能を使っていません。全体的なコードベースで、それをいつどのように使用するかについての誤った理解です。誤解されている可能性がある概念にもう少しコンテキストを追加します。
人々はrequire_onceが遅い関数であると考えるべきではありません。何らかの方法でコードを含める必要があります。require_once()
対require()
の速度は問題ではありません。それを盲目的に使用することで生じる可能性があるのは、パフォーマンスを妨げる警告に関するものです。コンテキストを考慮せずに広く使用すると、大量のメモリの浪費や無駄なコードにつながる可能性があります。
私が見てきたのは本当に悪いことです。巨大なモノリシックフレームワークがrequire_once()
、特に複雑なオブジェクト指向(OO)環境で、すべての間違った方法で使用する場合です。
require_once()
多くのライブラリで見られるように、すべてのクラスの先頭で使用する例を見てみましょう:
require_once("includes/usergroups.php");
require_once("includes/permissions.php");
require_once("includes/revisions.php");
class User{
// User functions
}
したがって、User
クラスは他の3つのクラスすべてを使用するように設計されています。けっこうだ!
しかし、今度は、訪問者がサイトを閲覧していて、ログインさえしておらず、フレームワークがロードされている場合はどうでしょうかrequire_once("includes/user.php");
。
これには、その特定のリクエスト中に使用しない1 + 3の不要なクラスが含まれています。これにより、肥大化したフレームワークは、5 MB以下ではなく、リクエストごとに40 MBを使用することになります。
クラスが誤用される他の方法は、クラスが他の多くの人によって再利用されるときです!helper
関数を使用するクラスが約50あるとします。helpers
読み込まれたときにこれらのクラスで確実に使用できるようにするには、次のようにします。
require_once("includes/helpers.php");
class MyClass{
// Helper::functions(); // etc..
}
ここ自体は何も問題はありません。ただし、1つのページ要求に15の同様のクラスが含まれている場合。あなたはrequire_once
15回走っています、または素晴らしいビジュアルのために:
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once()の使用は、不要な行を解析する必要があることに加えて、その関数を14回実行するパフォーマンスに技術的に影響します。同じような問題を抱えた他の使用頻度の高いクラスが10個しかないため、このようなかなり無意味な反復コードの100行以上を占める可能性があります。
そのためrequire("includes/helpers.php");
、代わりに、アプリケーションまたはフレームワークのブートストラップで使用する価値があります。ただし、すべてが相対的であるため、helpers
クラスの重みと使用頻度を15〜100行節約する価値があるかどうかはすべて異なりrequire_once()
ます。ただし、helpers
特定のリクエストでファイルを使用しない可能性がまったくない場合は、require
代わりにメインクラスに含める必要があります。持つrequire_once
各クラスには、個別にリソースの無駄になります。
このrequire_once
関数は必要なときに便利ですが、すべてのクラスをロードするためにどこでも使用する単一のソリューションと見なすべきではありません。
PEAR2 wiki(存在する場合)は、少なくともライブラリコードについて、オートロードを優先してすべてのrequire / includeディレクティブを破棄する正当な理由をリストするために使用されていました。これらは、pharのような代替のパッケージ化モデルが地平線上にあるときに、堅固なディレクトリ構造に縛られます。
更新:WikiのWebアーカイブバージョンは非常に醜いので、以下の最も説得力のある理由をコピーしました。
- (PEAR)パッケージを使用するには、include_pathが必要です。このため、PEARパッケージを別のアプリケーション内に独自のinclude_pathでバンドルしたり、必要なクラスを含む単一のファイルを作成したり、ソースコードを大幅に変更せずにPEARパッケージをpharアーカイブに移動することが難しくなります。
- トップレベルのrequire_onceが条件付きrequire_onceと混在している場合、これにより、APCなどのオペコードキャッシュ(PHP 6にバンドルされる)でキャッシュできないコードが生成される可能性があります。
- 相対require_onceには、include_pathがすでに正しい値に設定されている必要があるため、適切なinclude_pathがないとパッケージを使用できません
*_once()
関数STATあなたが含めているファイルがすでに含まれていたものと同じではないことを確認するために、すべての親ディレクトリを。それが減速の理由の一部です。
ベンチマークにはSiegeのようなツールを使用することをお勧めします。提案されたすべての方法を試し、応答時間を比較できます。
詳しくrequire_once()
はTech Your Universeをご覧ください。
require_once
and include_once
がrequire
and include
(または代替手段が存在する可能性がある場合)より遅い場合でも、ここではマイクロ最適化の最小レベルについて説明します。あなたの時間は、そのような何かを心配するよりも、不十分に書かれたループまたはデータベースクエリを最適化することに費やされた方がはるかに優れていますrequire_once
。
さて、require_once
インクルードをクリーンで整理された状態に保つことに注意を払う必要はないが、それ自体は関数自体、特に速度とは関係がないため、不適切なコーディングプラクティスを許容すると言って議論することができます。
明らかに、コードのクリーンさとメンテナンスの容易さのためにはオートローディングの方が優れていますが、これは速度とは関係がないことを明確にしたいと思います。
include、oliの代替、および__autoload();を使用してテストします。APCのようなものをインストールしてテストします。
定数を使用すると速度が上がるとは思えません。
PEARのドキュメントには、require、require_once、include、include_onceに関する推奨事項があると思います。私はそのガイドラインに従います。アプリケーションはより明確になります。
スピードとは関係ありません。それは優雅に失敗することです。
require_once()が失敗した場合、スクリプトは完了です。他には何も処理されません。include_once()を使用する場合、スクリプトの残りの部分はレンダリングを続行しようとするため、ユーザーはスクリプトで失敗したものに対して、それ以外の場合には賢くないでしょう。