我如何创建一个PHP库,使它不需要知道其他库文件的位置


How can I make a PHP library so it doesn't need to know where the other library files are?

我正在开发一个吉他和弦库。在库中的一些文件中,我有这样的内容:

require_once "lib/GuitarChord.php";
require_once "lib/Chord.php";
require_once "lib/Key.php";
require_once "lib/Tuning.php";

我怎样才能使这个库不需要知道其他库文件在哪里?

这样一个人可以在任何目录下拥有库文件?

为所有可能存在这些类的位置创建自动加载器

例如:

//AUTOLOADER
function class_autoloader($class) {
   // presumes classes are in './classes'
   $folders = array(
     './', './../', './../../'  
   );
   $directories = array(
     'classes','lib',  ''
   );
   $dir = dirname(__FILE__);
   $theClass = '/' . $folderedClass . '.php';

   foreach($folders as $folder){
       foreach($directories as $directory){
           $theInclude = $dir.$folder.$directory.$theClass;
           if (file_exists($theInclude) && include_once($theInclude)) {
              return TRUE;
           } 
       }
   }
  trigger_error("The class '$class' or the file '$theClass' failed to spl_autoload ", E_USER_WARNING);
  return FALSE;
}
spl_autoload_register('class_autoloader');

然后,如果你想加载Chord类,并且你知道它在你的lib文件夹中,自动加载器会在你执行以下操作时为你完成工作:

new Chord();

您可以使用spl_autoload_register附加许多不同的自动加载器回调

你应该检查一下名称空间和自动加载器

让我们假设你所有的类都在"GuitarChords"命名空间中-所以你可以创建类似于下面的自动加载函数(假设文件,你注册的自动加载器在"lib"的父目录下):

    spl_autoload_register(function($class){
       $namespace = explode('''', $class, 2);
          if ($namespace[0] === 'GuitarChords' && isset($namespace[1])) {
             include(__DIR__.DIRECTORY_SEPARATOR.'lib'.DIRECTORY_SEPARATOR.$namespace[1].'.class.php');
          }
     });

我认为最好为每个库集/命名空间专门注册一个自动加载函数。遍历目录并使用include_once, file_exists等可能会产生一些讨厌的IO开销,这取决于系统的复杂性。

如果您不想在一个文件中包含所有类,则必须在某个地方包含文件夹名称。你可以把它放在用户只需要设置一次的地方:

$lib_folder = "lib";
require_once $lib_folder . "/GuitarChord.php";
require_once $lib_folder . "/Chord.php";
require_once $lib_folder . "/Key.php";
require_once $lib_folder . "/Tuning.php";

至于处理不同类型的数据库,你可以做另一个设置,如$db_type,用户可以设置为"MYSQL","FILE","XML"等。当你调用数据库时,使用switch语句来查看他们正在使用的数据库方法,并相应地更改调用。

Edit: PHP的__autoload特性也值得一看

您可以尝试Zend AutoLoader

如果您的库使用了所有或大部分包含的类,那么请考虑将与您的库相关的所有类放在同一个文件中。其他解决方案只涉及添加更多代码,在这种情况下,你可能应该坚持使用当前的方法。

如果您希望将这些文件分开用于开发目的,那么无论如何都可以继续这样做,但您仍然可以将其打包成一个文件以供生产使用,以便人们轻松包含。