简化的递归PHP

时间:2014-05-14 06:17:52

标签: php class recursion include include-path

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

2 个答案:

答案 0 :(得分:4)

这是我为你自动加载的尝试。  我稍加修改了 Emil Condrea's Answer

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

Classes structure

如上所示,这些类被设置为单独的文件,以便显示。

现在接受 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(),我认为上述方法是正确的。更快。


更新

那天晚上我脑子里有脑波,想着; &#34; 为什么不扫描应用程序根目录并获取所有php文件然后运行一个函数来检查所述文件是否实际上包含一个类,以使其尽可能通用.. &#34; < / p>

所以我做了一些研究,从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;
}