简化递归PHP

简化递归PHP,php,class,recursion,include,include-path,Php,Class,Recursion,Include,Include Path,我一直在研究一种在php中使用_autoload()函数递归包含文件的方法。这样,您可以将类放到“classes”文件夹中的任何位置,并按子目录组织它们,但是_autoload函数仍然能够找到它们。这就是我到目前为止所得到的,我想知道是否有人能帮我简化它,这样它就不会那么长了它目前功能齐全,工作起来很有魅力。我只是想把它缩短。 <?php function readRecursive($path){ if(!is_dir($path)){ return false;

我一直在研究一种在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);
        }
    }
}

您可以使用 递归地遍历目录。这可能会简化您的功能

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;
}

这是我为你尝试的自动加载。 我稍微修改了

首先,我将向您展示我的类的文件结构:

正如您在上面所看到的,这些类被设置为单独的文件,以便显示

现在接受埃米尔的答案并稍加修改: (如果文件名类似于上面在文件结构中看到的“Class.php”)

将保证返回如下文件数组
[FILE\u NAME]=>[PATH\u 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(\uu文件))./model')

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;
}
允许我们运行
\uuu 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
,但对我来说,它似乎是在
\uu autoload()
函数中每次运行
getClasses()
函数的更好选择

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;
}
如果其他人有什么要补充的,请随意!我只是尝试了一下我自己的小方法,它没有缺点

注意:我以前使用的是
file_exists()
,我认为上面的方法是;快多了


更新 就在前几天晚上,我有一个脑波,我在想; “为什么不扫描应用程序根并获取所有php文件,然后运行一个函数来检查所述文件是否确实包含一个类,以使其尽可能通用…”

所以我做了一点研究,从php中发现了这个漂亮的小函数:

现在经过一点挖掘,我找到了这个答案:

经过一些修改后,
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)
,并对它们进行编辑


失败:每个类都必须具有唯一的类名/文件名。除非有人能帮忙修改以允许。

举个例子,请看你的函数将加载以
$name..class.php“
结尾的每个文件,不管整个目录树中有多少这样的文件。如果这是有意的,那么(对那些将要使用的人来说)Behavior为什么不使用composer autoloader是非常奇怪和不清楚的?begin的类映射。@AlmaDo否,它将只包括自动加载函数所需的特定文件。@AlmaDo它将包括两个foo类。然而,为什么任何开发人员都会有多个同名的类呢?。。如果这真的成为了一个问题,for循环中总会有一个中断,只包含函数出现的第一个循环。