10

PHP5 OOアプリケーションが(サイズとトラフィックの両方で)成長するにつれて、__ autoload()戦略を再検討することにしました。

ファイルには常に含まれるクラス定義によって名前が付けられるため、CustomerクラスはCustomer.php内に含まれます。以前は、適切な.phpファイルが見つかるまで、ファイルが存在する可能性のあるディレクトリを一覧表示していました。

これは非常に非効率的です。なぜなら、必要のない多数のディレクトリを通過し、すべてのリクエストでそれを実行する可能性があるためです(したがって、stat()呼び出しを大量に実行します)。

私の頭に浮かぶ解決策...

-ディレクトリ名を指定する命名規則を使用します(PEARと同様)。短所:スケーリングが大きすぎないため、クラス名がひどくなります。

-ロケーションのある種の事前に構築された配列を考え出します(propelはその__autoloadに対してこれを行います)。短所:新しいコードをデプロイする前に再構築が必要です。

-アレイを「オンザフライ」で構築し、キャッシュします。これは、必要なクラス名とディレクトリ構造を可能にし、新しいファイルがリストに追加されるだけで完全に柔軟であるため、最良の解決策のようです。懸念事項は次のとおりです。それをどこに保存するか、削除/移動されたファイルはどうですか。ストレージには、ディスクI / Oのオーバーヘッドがないため、APCを選択しました。ファイルの削除に関しては、とにかくどこにも必要としないので、問題ではありません。動きに関しては...それは未解決です(歴史的にはあまり頻繁に起こらなかったので無視します)。

他の解決策はありますか?

4

11 に答える 11

2

私もかなり長い間オートロードをいじっていましたが、ある種の名前空間オートローダーを実装することになりました (はい、PHP5.2 でも動作します)。

戦略は非常に単純です。最初に、をシミュレートする呼び出しを持つシングルトン クラス (ローダー) がありますimport。この呼び出しは、1 つのパラメーター (ロードする完全なクラス名) を取り、呼び出し元のファイル名を内部的に計算します ( を使用debug_backtrace())。呼び出しは、この情報を連想配列に格納して後で使用します (呼び出しファイルをキーとして使用し、各キーにインポートされたクラスのリストを使用します)。

典型的なコードは次のようになります。

<?php

    loader::import('foo::bar::SomeClass');
    loader::import('foo::bar::OtherClass');

    $sc = new SomeClass();

?>

autoload が起動されると、配列に格納された完全なクラス名が実際のファイルシステムの場所に変換され (ダブル コロンはディレクトリ セパレータに置き換えられます)、結果のファイル名が含まれます。

私はそれがあなたが求めていたものではないことを知っていますが、ローダーはファイルが正確にどこにあるかを直接知っているため、ディレクトリトラバーサルの問題を解決する可能性があります(明らかなパフォーマンスなしで、クラスをディレクトリに編成できる追加機能を使用)ペナルティ)。

いくつかの実用的な例を提供することはできますが、あまりにも恥ずかしがり屋なので、私のくだらないコードを一般に公開することはできません。上記の説明がお役に立てば幸いです...

于 2008-12-11T16:50:53.530 に答える
1

requireの前にfile_exists()チェックを行うことを除いて、最後のオプションとよく似たものを使用します。存在しない場合は、キャッシュを再構築してもう一度試してください。ファイルごとに追加の統計情報を取得しますが、移動は透過的に処理されます。物事を頻繁に移動したり名前を変更したりする迅速な開発に非常に便利です。

于 2009-01-10T03:28:12.880 に答える
1

うまく機能する 2 つの一般的なアプローチがあります。
まず、PEAR 標準のクラス命名構造を使用しているため、'_' を / に置き換えるだけでクラスを見つけることができます。

http://pear.php.net/manual/en/pear2cs.rules.php

または、php クラスのディレクトリを検索し、クラス名をファイルにマップすることもできます。クラス マップをキャッシュに保存して、ページが読み込まれるたびに検索ディレクトリを保存できます。
Symfony フレームワークはこれらのアプローチを使用します。

一般的には、標準構造に従うほうが単純であり、何もキャッシュする必要がないため、推奨されるガイドラインに従っていることになります。

于 2008-12-12T01:36:49.773 に答える
1

私は過去にこのソリューションを使用したことがあり、参考のためにブログに書いていますが、一部の人にとっては興味深いかもしれません...

ここにあります

于 2009-07-31T19:46:16.477 に答える
0

CodeIgniterは、load_class関数と同様のことを行います。正しく思い出せば、それはオブジェクトの配列を保持する静的関数です。関数の呼び出しは次のとおりです。


 load_class($class_name, $instansiate);

だからあなたの場合


 load_class('Customer', TRUE);

これにより、Customerクラスのインスタンスがobjects配列にロードされます。

関数は非常に簡単でした。申し訳ありませんが、クラスの名前を思い出せません。ただし、Routingクラス、Benchmarkクラス、URIクラスなど、ロードされるクラスがいくつかあったことを思い出します。

于 2008-12-11T16:14:42.137 に答える
0
function __autoload($class_name) {
   $class_name = strtolower($class_name);
   $path       = "../includes/{$class_name}.php";
   if (file_exists($path)) {
       require_once($path);
   } else {
       die("The file {$class_name}.php could not be found!");
   }
}
于 2014-12-14T18:08:50.937 に答える
0

I have specific naming conventions for each 'type' of class (controllers, models, library files, and so on...), so currently I do something similar to:

function __autoload($class){
    if($class matches pattern_1 and file_exists($class.pattern_1)){
        //include the file somehow
    } elseif($class matches pattern_2 and file_exists($class.pattern_2)){
        //include the file somehow
    } elseif(file_exists($class.pattern_3)){
        //include the file somehow
    } else {
       //throw an error because that class does not exist?
    }
}
于 2009-09-14T23:55:27.080 に答える
0

古いスレッドですが、とにかくここで自分のメソッドを公開できると思いました。誰かを助けることができるかもしれません。これは、たとえば__autoload()、Web サイトのエントリ ポイントで定義する方法です。/path/to/root/www/index.php

function __autoload($call) {
    require('../php/'.implode('/', explode('___', $call)).'.php');
}

すべての PHP ファイルはツリーで編成されています

/パス/へ/ルート/php
  /アプリケーション
    /Webサイト
      サーバー.php
  /モデル
    ユーザー.php
  /ライブラリ
    /HTTP
      クライアント.php
    Socket.php

クラス名は次のとおりです。

アプリケーション___ウェブサイト___サーバー
モデル___ユーザー
ライブラリ___HTTP___クライアント
ライブラリ___ソケット

これは高速で、ファイルが存在しない場合はクラッシュし、エラー ログに不足しているファイルが表示されます。少し厳しいように思えるかもしれませんが、間違ったクラスを使用しようとすると、それはあなたの問題です.

NB : PHP 5 < 5.3 用だったので、PHP 5.3 では名前空間を使用できます。区切り文字として 3 _ を使用した理由は、5.3 の名前空間の使用を簡単に置き換えるためです。

于 2010-06-16T13:19:36.593 に答える
0

APC を使用している場合は、オペコード キャッシュを有効にする必要があります。これは、あなたが採用しているどのクラス/ファイル戦略よりも、パフォーマンスに大きなメリットがあり、より透過的なソリューションになると思います。

2 番目の提案は、開発が最も簡単なクラス/ファイル戦略を使用することですが、実稼働サイトでは、最も頻繁に使用されるクラスを 1 つのファイルに連結し、すべての要求中に読み込まれる (または APC でキャッシュされる) ようにする必要があります。

クラスのセットを増やして、いくつかのパフォーマンス実験を行います。ファイル I/O を削減する利点は非常に大きいため、すべてのクラスを 1 つのファイルにまとめることは、すべての要求ですべてのクラスを必要としない場合でも、実質的には有利であることがわかるでしょう。

于 2008-12-11T17:49:22.323 に答える
-1

ネイティブだけでなく、Zend_LoaderregisterAutoload()を使用)を使用して調査しました__autoload()か?私はZend_Loaderを使用して満足していますが、パフォーマンスの観点からは見ていません。ただし、このブログ投稿では、パフォーマンス分析が行われているようです。これらの結果を現在のオートローダーでの社内パフォーマンステストと比較して、期待に応えることができるかどうかを確認できます。

于 2008-12-11T16:27:22.377 に答える
-3
function __autoload( $class )
{
    $patterns = array( '%s.class.php', '%s.interface.php' );

    foreach( explode( ';', ini_get( 'include_path' ) ) as $dir )
    {
        foreach( $patterns as $pattern )
        {
            $file    = sprintf( $pattern, $class );
            $command = sprintf( 'find -L %s -name "%s" -print', $dir, $file );
            $output  = array();
            $result  = -1;

            exec( $command, $output, $result );

            if ( count( $output ) == 1 )
            {
                require_once( $output[ 0 ] );
                return;
            }
        }
    }

    if ( is_integer( strpos( $class, 'Exception' ) ) )
    {
        eval( sprintf( 'class %s extends Exception {}', $class ) );
        return;
    }

    if ( ! class_exists( $class, false ) )
    {
        // no exceptions in autoload :(
        die( sprintf( 'Failure to autoload class: "%s"', $class ) );
        // or perhaps: die ( '<pre>'.var_export( debug_backtrace(), true ).'</pre>' );        
    }
}

ディレクトリを反復するための、posixに依存しない他の方法を見つけることもできますが、これは私が使用しているものです。

include_path (php.ini または .htaccess で設定) 内のすべてのディレクトリを走査して、クラスまたはインターフェイスを見つけます。

于 2008-12-12T14:32:16.047 に答える