【问题标题】:Best Way To Autoload Classes In PHP在 PHP 中自动加载类的最佳方法
【发布时间】:2013-07-22 07:02:23
【问题描述】:

我正在做一个项目,我的文件结构如下:

index.php
|---lib
|--|lib|type|class_name.php
|--|lib|size|example_class.php

我想自动加载类,class_name 和 example_class(命名与 PHP 类相同),以便在 index.php 中类已经被实例化,所以我可以这样做:

$class_name->getPrivateParam('name');

我在网上查了一下,但找不到正确的答案 - 谁能帮帮我?

编辑

感谢您的回复。让我扩展我的场景。我正在尝试编写一个 WordPress 插件,该插件可以放入项目中,并通过将类放入文件夹“功能”中添加附加功能,例如,在插件内部。永远不会有 1000 个类,一次推送可能 10 个?

我可以编写一个方法来遍历“lib”文件夹的文件夹结构,包括每个类,然后将其分配给一个变量(类名),但我认为这不是一种非常有效的方法但这似乎是实现我需要的最佳方式?

【问题讨论】:

    标签: php spl-autoloader


    【解决方案1】:

    在文件中执行此操作并将其命名为 (mr_load.php) 这是你所有的课程

    spl_autoload_register(function($class){ 
         $path = '\Applicaton/classes/';
        $extension = '.php';
        $fileName = $path.$class.$extension;
        include $_SERVER['DOCUMENT_ROOT'].$fileName;
    })
    

    ;

    • 然后创建另一个文件并包含 mr_load.php; $load_class= 新巴士站(); $load_class->method()

    【讨论】:

      【解决方案2】:
      spl_autoload_register(function ($class_name) {
          $iterator = new DirectoryIterator(dirname(__FILE__));
          $files = $iterator->getPath()."/classes/".$class_name.".class.php";
          
          if (file_exists($files)) {
              include($files);
          } else {
             die("Warning:The file {$files}.class.php could not be found!");
          
          }
      });
      

      【讨论】:

        【解决方案3】:

        您可以使用此自动加载器指定对命名空间友好的自动加载。

        <?php
        spl_autoload_register(function($className) {
            $file = __DIR__ . '\\' . $className . '.php';
            $file = str_replace('\\', DIRECTORY_SEPARATOR, $file);
            if (file_exists($file)) {
                include $file;
            }
        });
        

        确保正确指定类文件的位置。

        Source

        【讨论】:

          【解决方案4】:
          function __autoload($class_name) {
             $class_name = strtolower($class_name);
             $path       = "{$class_name}.php";
             if (file_exists($path)) {
                 require_once($path);
             } else {
                 die("The file {$class_name}.php could not be found!");
             }
          }
          

          更新: __autoload() 自 PHP 7.2 起已弃用

          【讨论】:

          • 为什么这是最好的方法?
          • 此样式已被 PSR 标准弃用。
          • PHP 不推荐使用。 PSR 不相关。
          • 不鼓励使用 __autoload(),将来可能会弃用或删除:php.net/manual/en/language.oop5.autoload.php
          • __autoload() 自 PHP 7.2 起已弃用。
          【解决方案5】:

          我在这里有一个用于自动加载和初始化的示例。
          基本上是一个更好的 spl_autoload_register 版本,因为它只会在您初始化类时尝试要求类文件。
          在这里,它会自动获取类文件夹中的每个文件,需要这些文件并对其进行初始化。您所要做的就是将类命名为与文件相同。
          index.php

          <?php
          require_once __DIR__ . '/app/autoload.php';
          
          $loader = new Loader(false);
          
          User::dump(['hello' => 'test']);
          

          autoload.php

          <?php
          class Loader 
          {
          
              public static $library;
          
              protected static $classPath = __DIR__ . "/classes/";
          
              protected static $interfacePath = __DIR__ . "/classes/interfaces/";
          
              public function __construct($requireInterface = true) 
              {
                  if(!isset(static::$library)) {
                      // Get all files inside the class folder
                      foreach(array_map('basename', glob(static::$classPath . "*.php", GLOB_BRACE)) as $classExt) {
                          // Make sure the class is not already declared
                          if(!in_array($classExt, get_declared_classes())) {
                              // Get rid of php extension easily without pathinfo
                              $classNoExt = substr($classExt, 0, -4); 
                              $file = static::$path . $classExt;
          
                              if($requireInterface) {
                                  // Get interface file
                                  $interface = static::$interfacePath . $classExt;
                                  // Check if interface file exists
                                  if(!file_exists($interface)) {
                                      // Throw exception
                                      die("Unable to load interface file: " . $interface);
                                  }
          
                                  // Require interface
                                  require_once $interface;
                                  //Check if interface is set
                                  if(!interface_exists("Interface" . $classNoExt)) {
                                      // Throw exception
                                      die("Unable to find interface: " . $interface);
                                  }
                              }
          
                              // Require class
                              require_once $file;
                              // Check if class file exists
                              if(class_exists($classNoExt)) {
                                  // Set class        // class.container.php
                                  static::$library[$classNoExt] = new $classNoExt();
                              } else {
                                  // Throw error
                                  die("Unable to load class: " . $classNoExt);
                              }
          
                          }
                      }
                  }
              }
          
              /*public function get($class) 
              {
                  return (in_array($class, get_declared_classes()) ? static::$library[$class] : die("Class <b>{$class}</b> doesn't exist."));
              }*/
          }
          

          您可以通过一些编码轻松管理,也可以要求不同文件夹中的类。
          希望这对你有用。

          【讨论】:

          • 适用于具有许多许多类的大型应用程序吗?不会影响内存性能吗?
          【解决方案6】:

          如果您需要自动加载类,请使用 SPL 自动加载的命名空间和类名约定,这样可以节省重构时间。 当然,您需要将每个类实例化为一个对象。 谢谢。

          就像在这个线程中: PHP Autoloading in Namespaces

          但是如果你想要一个复杂的解决方法,请看一下 Symfony 的自动加载类: https://github.com/symfony/ClassLoader/blob/master/ClassLoader.php

          或者像这样(我在我的一个项目中做过):

          <?
          spl_autoload_register(function($className)
          {
              $namespace=str_replace("\\","/",__NAMESPACE__);
              $className=str_replace("\\","/",$className);
              $class=CORE_PATH."/classes/".(empty($namespace)?"":$namespace."/")."{$className}.class.php";
              include_once($class);
          });
          ?>
          

          然后你可以像这样实例化你的类:

          <?
          $example=new NS1\NS2\ExampleClass($exampleConstructParam);
          ?>
          

          这是你的课程(在 /NS1/NS2/ExampleClass.class.php 中找到):

          <?
          namespace NS1\NS2
          {
              class Symbols extends \DB\Table
              {
                  public function __construct($param)
                  {
                      echo "hello!";
                  }
              }
          }
          ?>
          

          【讨论】:

          • 这看起来很理想,但它不会自动扫描文件结构并实例化类。我应该在迭代器周围添加第二个代码片段,然后实例化该类吗?
          • @Sjwdavies,通过您的文件结构的迭代是您自己的 - 如果您想使用命名空间(建议),它似乎不是必需的部分。
          • @Sjwdavies,但可以肯定的是,如果您想自动加载所有类,您必须用文件结构迭代器包装第二个代码 sn-p。但是想想并记住脚本内存的使用情况。
          • @Sjwdavies 但是如果你真的想预加载一些类,我建议你在它的文件名中添加“auto”这个词(比如 Hello.class.auto.php),这样你就可以轻松处理它在你的包装器中自动加载。而且您不需要自动加载非静态类(如 Hello2.class.php)
          • And of course, you will need to instantiate every class as an object. -> 我不清楚您是否将其视为劣势的优势,以及为什么。
          【解决方案7】:

          如果您可以访问命令行,则可以在 classMap 部分使用 composer 进行尝试,如下所示:

          {
              "autoload": {
                  "classmap": ["yourpath/", "anotherpath/"]
              }
          }
          

          那么你有一个 wordpress 插件可以在 wordpress cli 中启用作曲家:http://wordpress.org/plugins/composer/

          【讨论】:

            【解决方案8】:

            http://php.net/manual/de/function.spl-autoload-register.php

            spl_autoload_register(function ($class) {
                @require_once('lib/type/' . $class . '.php');   
                @require_once('lib/size/' . $class . '.php');
            });
            

            【讨论】:

            • 我不想使用它,因为我必须指定每个文件,这违背了我试图自动执行的对象。
            • 通常你包含 1 个包含所有子类的主库文件。您不必指定每个文件 - 只需指定文件夹。主类有多少个文件夹?即使您有更多文件夹,也可以使用 readdir() 遍历所有文件夹
            • @DanFromGermany:我想说你通常包含一个文件,它是一个自动加载器实例,你配置它(注册前缀、后缀、命名空间、包含路径等),然后 类会在时机成熟时加载任何需要加载的类
            • @EliasVanOotegem 这就是我的意思。但是您不包含 10000 个单个文件
            • 为什么这是最好的方法?
            猜你喜欢
            • 1970-01-01
            • 2018-07-22
            • 2016-09-12
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多