web-dev-qa-db-ja.com

異なるフォルダーからクラスを自動ロードする

これがcontrollersフォルダー内のすべてのクラスを自動ロードする方法です。

# auto load controller classes
    function __autoload($class_name) 
    {
        $filename = 'class_'.strtolower($class_name).'.php';
        $file = AP_SITE.'controllers/'.$filename;

        if (file_exists($file) == false)
        {
            return false;
        }
        include ($file);
    }

しかし、modelsフォルダーにもクラスがあり、それらも自動ロードしたいのですが、どうすればよいですか?上記のオートロードを複製して、パスをmodels/に変更するだけです(ただし、これは繰り返しではありませんか?)。

ありがとう。

編集:

これらは、コントローラーフォルダー内のクラスファイル名です。

class_controller_base.php
class_factory.php
etc

これらは、モデルフォルダー内のクラスファイル名です。

class_model_page.php
class_model_parent.php
etc

これは、通常、コントローラークラスクラスに名前を付ける方法です(アンダースコアとローキャップを使用します)。

class controller_base 
{
...
}

class controller_factory
{
...
}

これは通常、モデルクラスに名前を付ける方法です(アンダースコアとローキャップを使用します)。

class model_page 
    {
    ...
    }

    class model_parent
    {
    ...
    }
42
laukok

アンダースコア(___)がディレクトリ区切り文字(_/_)に変換されるように、クラスに名前を付ける必要があります。 ZendやKohanaなど、いくつかのPHPフレームワークがこれを行います。

したがって、クラスに_Model_Article_という名前を付け、ファイルを_classes/model/article.php_に配置すると、オートロードが実行されます...

_function __autoload($class_name) 
{
    $filename = str_replace('_', DIRECTORY_SEPARATOR, strtolower($class_name)).'.php';

    $file = AP_SITE.$filename;

    if ( ! file_exists($file))
    {
        return FALSE;
    }
    include $file;
}
_

また、 spl_autoload_register() を使用して、任意の関数を自動読み込み関数にすることができます。また、より柔軟で、複数の自動ロードタイプ関数を定義できます。

複数の自動ロード関数が必要な場合、spl_autoload_register()はこれを許可します。自動ロード機能のキューを効果的に作成し、定義された順に各機能を実行します。対照的に、__ autoload()は一度しか定義できません。

編集

注:__ autoloadは、PHP 7.2。 0.この機能に依存することは強くお勧めしません。詳細についてはPHPのドキュメントを参照してください。 http://php.net/manual/en/function.autoload.php

27
alex

クラスの命名規則として_controller_*****_と_model_*****_を使用しているようです。

素晴らしい 記事 を読みました。これは、PHPのnamespaceを使用した別の命名規則を示しています。

クラスをどこに置くかは関係ないので、このソリューションが気に入っています。 ___autoload_は、ファイル構造内のどこにいてもそれを見つけます。また、クラスを好きなように呼び出すことができます。コードが機能するためにクラスの命名規則は必要ありません。

たとえば、次のようなフォルダ構造を設定できます。

  • 応用/
    1. controllers /
      • Base.php
      • Factory.php
    2. モデル/
      • Page.php
      • Parent.php

クラスは次のように設定できます。

_<?php
namespace application\controllers;
class Base {...}
_

そして:

_<?php
namespace application\models;
class Page {...}
_

オートローダーは次のようになります(または最後に「オートロードに関する注意事項」を参照)。

_function __autoload($className) {
    $file = $className . '.php';
    if(file_exists($file)) {
        require_once $file;
    }
}
_

次に... 3つの方法でクラスを呼び出すことができます。

_$controller = new application\controllers\Base();
$model = new application\models\Page();
_

または、

_<?php
use application\controllers as Controller;
use application\models as Model;

...

$controller = new Controller\Base();
$model = new Model\Page();
_

または、

_<?php
use application\controllers\Base;
use application\models\Page;

...

$controller = new Base();
$model = new Page();
_

編集-オートロードに関する注意:

私のメインのオートローダーは次のようになります:

_// autoload classes based on a 1:1 mapping from namespace to directory structure.
spl_autoload_register(function ($className) {

    # Usually I would just concatenate directly to $file variable below
    # this is just for easy viewing on Stack Overflow)
        $ds = DIRECTORY_SEPARATOR;
        $dir = __DIR__;

    // replace namespace separator with directory separator (prolly not required)
        $className = str_replace('\\', $ds, $className);

    // get full name of file containing the required class
        $file = "{$dir}{$ds}{$className}.php";

    // get file if it is readable
        if (is_readable($file)) require_once $file;
});
_

このオートローダーは、クラス名とディレクトリ構造の直接1:1マッピングです。名前空間はディレクトリパスであり、クラス名はファイル名です。したがって、上記で定義されたクラスapplication\controllers\Base()は、ファイル_www/application/controllers/Base.php_をロードします。

ルートディレクトリにあるbootstrap.phpファイルにオートローダーを配置します。これは、直接含めるか、php.iniを auto_prepend_file に変更して、すべてのリクエストに自動的に含めることができます。

spl_autoload_register を使用すると、複数の自動ロード関数を登録して、どの方法でもクラスファイルをロードできます。つまり、クラスの一部またはすべてを1つのディレクトリに配置するか、または 1つのファイルに名前空間クラス を配置することができます。非常に柔軟:)

61
br3nt

「適切な」自動ロードスクリプトとコード構造について言及する必要があるため、次のCAREFULLYをお読みください。


心に留めて:

  • クラス名 === ファイル名
  • ファイルごとに1つのクラスのみ

例:Example.phpに含まれるもの

class Example {}
  • 名前空間 === ディレクトリ構造

例:/Path1/Path2/Example.phpが一致

namespace Path1\Path2;
class Example {}
  • 衝突を避けるためにルート名前空間が存在する必要があります

例:/Path1/Path2/Example.php with root:

namespace APP\Path1\Path2;
class Example {}
  • 手動で定義されたパスまたはディレクトリリストを使用しないで、ローダーを一番上のディレクトリに向けるだけです
  • ローダーを可能な限り高速に保ちます(ファイルを含めるだけで十分なため)

これを念頭に置いて、私は次のスクリプトを作成しました。

function Loader( $Class ) {
    // Cut Root-Namespace
    $Class = str_replace( __NAMESPACE__.'\\', '', $Class );
    // Correct DIRECTORY_SEPARATOR
    $Class = str_replace( array( '\\', '/' ), DIRECTORY_SEPARATOR, __DIR__.DIRECTORY_SEPARATOR.$Class.'.php' );
    // Get file real path
    if( false === ( $Class = realpath( $Class ) ) ) {
        // File not found
        return false;
    } else {
        require_once( $Class );
        return true;
    }
}

どこに置くか.

  • /Loader.php <-ローダーがあります
  • / Controller/... <-ここにあなたのものを置く
  • / Model/... <-またはここなど
  • / ...

覚え書き:

  • ルート名前空間を使用する場合、ローダーもこの名前空間に存在する必要があります
  • ニーズに合わせて$ Classのプレフィックスを付けることができます(controller_base {}-> class_controller_base.php)
  • __DIR__をクラスファイルを含む絶対パスに変更できます(例: "/ var/www/classes")
  • 名前空間を使用しない場合、すべてのファイルはローダーと同じディレクトリになければなりません(悪い!)

ハッピーコーディング;-)


他の回答でのちょっとしたレビュー:これISちょうど私の個人的な意見-攻撃意図なし!

https://stackoverflow.com/a/5280353/626731 @alexの良い解決策ですが、クラス名に悪いファイル構造の代価を払わせないでください;-)これは名前空間の仕事です

https://stackoverflow.com/a/5280510/626731 @ Mark-Eirichそれは動作しますが、このようにするのはかなり厄介な/ ugly/slow/stiff [..]スタイルです。

https://stackoverflow.com/a/5284095/626731 @tealou彼の問題が解決されるため、これはこれまでで最も明確なアプローチです:-) ..

https://stackoverflow.com/a/9628060/626731 @ br3ntこれは私の視点を反映していますが、お願いします(!).. strtrを使用しないでください!! ....

https://stackoverflow.com/a/11866307/626731 @Iscariot ..あなたに、ちょっとした "you-know-bullshit-benchmark:

Time        sprintf preg_replace strtr    str_replace v1 str_replace v2
08:00:00 AM 1.1334  2.0955       48.1423  1.2109         1.4819
08:40:00 AM 1.0436  2.0326       64.3492  1.7948         2.2337
11:30:00 AM 1.1841  2.5524       62.0114  1.5931         1.9200
02:00:00 PM 0.9783  2.4832       52.6339  1.3966         1.4845
03:00:00 PM 1.0463  2.6164       52.7829  1.1828         1.4981
Average     1.0771  2.3560       55.9839  1.4357         1.7237


Method         Times Slower (than sprintf)
preg_replace   2.19
strtr          51.97
str_replace v1 1.33
str_replace v2 1.6

ソース: http://www.simplemachines.org/community/index.php?topic=175031.

Questions? ..(しかし、彼は実際にフルパスについては正しい)

https://stackoverflow.com/a/12548558/626731 @ Sunil-Kartikey https://stackoverflow.com/a/17286804/626731 @jurrien

タイムクリティカルな環境では絶対にループしないでください! OSでファイルを検索しないでください! - スロー

https://stackoverflow.com/a/21221590/626731 @sagits .. Marksよりもはるかに良い;-)

7
DerDu
function autoload($className)
{
//list comma separated directory name
$directory = array('', 'classes/', 'model/', 'controller/');

//list of comma separated file format
$fileFormat = array('%s.php', '%s.class.php');

foreach ($directory as $current_dir)
{
    foreach ($fileFormat as $current_format)
    {

        $path = $current_dir.sprintf($current_format, $className);
        if (file_exists($path))
        {
            include $path;
            return ;
        }
    }
}
}
spl_autoload_register('autoload');
4
Sunil Kartikey

これが私の解決策です

/**
     * autoload classes 
     *
     *@var $directory_name
     *
     *@param string $directory_name
     *
     *@func __construct
     *@func autoload
     *
     *@return string
    */
    class autoloader
    {
        private $directory_name;

        public function __construct($directory_name)
        {
            $this->directory_name = $directory_name;
        }

        public function autoload($class_name) 
        { 
            $file_name = 'class_'.strtolower($class_name).'.php';

            $file = AP_SITE.$this->directory_name.'/'.$file_name;

            if (file_exists($file) == false)
            {
                return false;
            }
            include ($file);
        }
    }

    # nullify any existing autoloads
    spl_autoload_register(null, false);

    # instantiate the autoloader object
    $classes_1 = new autoloader('controllers');
    $classes_2 = new autoloader('models');

    # register the loader functions
    spl_autoload_register(array($classes_1, 'autoload'));
    spl_autoload_register(array($classes_2, 'autoload'));

それが最良の解決策であるかどうかはわかりませんが、完全に機能するようです...

どう思いますか??

3
laukok

私の@Mark Eirichの回答:

    function myload($class) {
      $controllerDir = '/controller/';
      $modelDir = '/model/';
      if (strpos($class, 'controller') !== false) {              
        $myclass = $controllerDir . $class . '.php';
      } else {
        $myclass = $modelDir . $class . '.inc.php';
      }
          if (!is_file($myclass)) return false;
          require_once ($myclass);

    }

    spl_autoload_register("myload");

私の場合、名前にキーワードがあるのはコントローラークラスのみで、ニーズに合わせて調整します。

2
sagits

簡単な答え私はそれらの複雑なコードを書き留めることなく、名前空間を使用することなくあなたに与えることができます(これがあなたを混乱させる場合)

サンプルコード。100%動作します。

function __autoload($class_name){
$file = ABSPATH . 'app/models/' . $class_name . '.php';
if(file_exists($file)){
    include $file;
}else{
    $file = ABSPATH . 'app/views/' . $class_name . '.php';
    if(file_exists($file)){
        include $file;
    }else{
        $file = ABSPATH . 'app/controllers/' . $class_name . '.php';
        include $file;
    }
}

ロジック自体は説明できると思います。歓声メイト!お役に立てれば :)

私がやることは次のとおりです。

function __autoload($class_name) {
    $class_name = strtolower($class_name);
    $filename = 'class_'.$class_name.'.php';

    if (substr($class_name, 0, 5) === 'model') {
        $file = AP_SITE.'models/'.$filename;
    } else $file = AP_SITE.'controllers/'.$filename;

    if (!is_file($file)) return false;
    include $file;
}

class_controller_*.phpclass_model_*.phpのように一貫してファイルに名前を付けている限り、これはうまく機能するはずです。

1
Mark Eirich

__autoload()関数は推奨されていないため、使用しないでください。代わりにspl_autoload()、spl_autoload_register()を使用してください。 __autoload()はただ1つのクラスをロードできますが、spl_autoload()は複数のクラスを取得できます。さらに、将来的には__autoload()は非推奨になる可能性があります。より多くのものは http://www.php.net/manual/en/function.spl-autoload.php で見つけることができます

0
asi_x

このスクリプトには名前の規則はありませんが、このスレッドは既に少し古いので、誰かが可能な答えを探している場合に備えて、これは私がやったことです:

function __autoload($name) {
    $dirs = array_filter(glob("*"), 'is_dir');

    foreach($dirs as $cur_dir) {
        dir_searcher($cur_dir, $name);
    }

}

function dir_searcher($cur_dir, $name) {

    if(is_file("$cur_dir/$name.php")) {
        require_once "$cur_dir/$name.php";
    }

    $dirs = array_filter(glob($cur_dir."/*"), 'is_dir');
    foreach($dirs as $cdir) {
        dir_searcher("$cdir", $name);
    }
}

本当に最適かどうかはわかりませんが、dirを再帰的に読み取ってフォルダーを検索します。創造的なstr_replace関数を使用すると、名前の制限を取得できます。

0
jurrien

これを使用します。基本的に、フォルダー構造(MVCなど)をシリアル化された配列の定数として定義します。次に、オートロードクラスで配列を呼び出します。私にとって効率的に動作します。

別の関数を使用してフォルダー配列を作成することもできますが、MVCの場合は手動で入力することもできます。

これが機能するには、クラスを呼び出す必要があります...... class.classname.php

  //in your config file
    //define class path and class child folders
    define("classPath","classes");
    define("class_folder_array", serialize (array ("controller", "model", "view")));


  //wherever you have your autoload class
    //autoload classes
    function __autoload($class_name) {
    $class_folder_array = unserialize (class_folder_array);
    foreach ($class_folder_array AS $folder){
        if(file_exists(classPath."/".$folder.'/class.'.$class_name.'.php')){require_once classPath."/".$folder.'/class.'.$class_name.'.php';break;}
    }



    }
0
Andy RS

誰もが、インターネットから取得したコードからのものをコピーして貼り付けています(選択した回答を除きます)。それらはすべて文字列置換を使用します。

文字列置換はstrtrの4倍遅くなります。代わりに使用する必要があります。

また、OSがパスを解決する時間が短くなるため、クラスをオートロードに含める場合はフルパスを使用する必要があります。

0
Case