我一直在研究一种在php中使用__autoload()函数递归包含文件的方法。这样,您可以将您的类放在“classes”文件夹中的任何位置,并按子目录组织它们,但__autoload函数仍然可以找到它们。这是我到目前为止所得到的,并且想知道是否有人可以帮助我简化它以使它不那么冗长。 目前功能完全正常,并且像魅力一样。我只是想缩短它。
<?php
function readRecursive($path){
if(!is_dir($path)){
return false;
}
$dir = glob($path ."/*");
$retArr = array();
foreach($dir as $f){
if(is_dir($f)){
$m = readRecursive($f);
foreach($m as $n){
$retArr[] = $n;
}
}else{
$retArr[] = $f;
}
}
return $retArr;
}
function endsWith($haystack, $needle){
return $needle === "" || substr($haystack, -strlen($needle)) === $needle;
}
/* Set up AutoLoading for object classes */
function __autoload($class_name){
$classes = readRecursive("classes");
foreach($classes as $class){
if(endsWith(strtolower($class), strtolower($class_name.".class.php"))){
include_once ($class);
}
}
}
&GT;
答案 0 :(得分:4)
这是我为你自动加载的尝试。 我稍加修改了 Emil Condrea's Answer 。
首先,我将向您展示我的课程的文件结构:
如上所示,这些类被设置为单独的文件,以便显示。
现在接受 Emil的回答并略微更改它: (如果文件名类似于&#34; Class.php&#34;如上文中文件结构所示)
function getClasses($path) {
$files = array();
$dir_iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS), RecursiveIteratorIterator::SELF_FIRST);
foreach ($dir_iterator as $item) {
$pathname = $item->getPathName();
$filename = $item->getFileName();
if ($item->isDir()) {
getClasses($item);
} else {
$files[$filename] = $pathname;
}
}
return $files;
}
保证返回一系列文件,例如以下 [FILE_NAME] => [PATH_NAME]
:
Array
(
[Error.php] => /home2/DERP/public_html/something.com/watch/model/Site/Error.php
[Form.php] => /home2/DERP/public_html/something.com/watch/model/Site/Form.php
[Site.php] => /home2/DERP/public_html/something.com/watch/model/Site/Site.php
[Db.php] => /home2/DERP/public_html/something.com/watch/model/Database/Db.php
[Db_pdo.php] => /home2/DERP/public_html/something.com/watch/model/Database/Db_pdo.php
[Session.php] => /home2/DERP/public_html/something.com/watch/model/Security/Session.php
[Auth.php] => /home2/DERP/public_html/something.com/watch/model/Security/Auth.php
[Input.php] => /home2/DERP/public_html/something.com/watch/model/Security/Input.php
[Postcode.php] => /home2/DERP/public_html/something.com/watch/model/Postcode.php
[Rep.php] => /home2/DERP/public_html/something.com/watch/model/User/Rep.php
[User.php] => /home2/DERP/public_html/something.com/watch/model/User/User.php
[Notifications.php] => /home2/DERP/public_html/something.com/watch/model/User/Notifications.php
[Log.php] => /home2/DERP/public_html/something.com/watch/model/Log/Log.php
[Hook.php] => /home2/DERP/public_html/something.com/watch/model/Hook.php
)
现在可以通过以下方式调用:
<强> getClasses(realpath(dirname(__FILE__)) . '/model')
强>
允许我们运行__autoload()
,如下所示:
$model_classes = getClasses(realpath(dirname(__FILE__)) . '/model');
function __autoload($class_name) {
global $model_classes;
$filename = ucfirst($class_name) . '.php';
$model = $filename;
if (!isset($model_classes[$model])) {
// dead
return false;
} else {
// include first file (model)
include($model_classes[$model]);
}
}
显然你不应该使用global
但对我来说,它似乎是在getClasses()
函数中每次运行__autoload()
函数的一个更好的选择。
如果其他人有任何要添加的内容,请随意!我只是尝试了我自己的小方法,它没有错!#/ p>
file_exists()
,我认为上述方法是正确的。更快。
所以我做了一些研究,从php发现了这个漂亮的小功能:token_get_all()
现在经过一番挖掘后我发现了这个答案:Determine class in file...
经过一些修改后,getClasses()
函数现在看起来像这样:
function getClasses($path) {
$files = array();
$dir_iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS), RecursiveIteratorIterator::SELF_FIRST);
foreach ($dir_iterator as $item) {
$pathname = $item->getPathName();
$filename = $item->getFileName();
if ($item->isDir()) {
get_classes($item);
} else {
if (substr($filename, -4) === '.php') {
if (get_php_classes(file_get_contents($pathname))) {
$files[$filename] = $pathname;
}
}
}
}
return $files;
}
从上述问题中添加了这个新功能:
function get_php_classes($php_code) {
$tokens = token_get_all($php_code);
$class_token = false;
foreach ($tokens as $token) {
if (is_array($token)) {
if ($token[0] == T_CLASS) {
$class_token = true;
} else if ($class_token && $token[0] == T_STRING) {
$classes[] = $token[1];
// $class_token = false;
}
}
}
return $class_token;
}
现在,您可以简单地运行$classes = getClasses(ROOTPATH)
并通过它们进行操作。
DOWNFALL:每个类都必须具有唯一的类名和 / 或文件名。除非有人能够修改允许。
答案 1 :(得分:0)
你可以使用 RecursiveDirectoryIterator以递归方式遍历目录。这可能会简化您的功能。
function getRecursive($path){
$files = array();
$dir_iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS),RecursiveIteratorIterator::SELF_FIRST);
foreach ($dir_iterator as $item) {
$subPath = $dir_iterator->getSubPathName();
if($item->isDir())
$files[$subPath] = array();
else
$files[$subPath][] = $subPath;
}
return $files;
}