【问题标题】:Simplified Recursive PHP简化的递归 PHP
【发布时间】:2014-05-14 06:17:52
【问题描述】:

我一直在研究一种使用 php.ini 中的 __autoload() 函数递归地包含文件的方法。这样,您可以将您的类放在“类”文件夹中的任何位置,并按子目录组织它们,但 __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);
        }
    }
}

?>

【问题讨论】:

  • 关于一个想法,请参阅stackoverflow.com/questions/3226519/…
  • 您的函数将加载每个以$name.".class.php" 结尾的文件——无论整个目录树中存在多少这样的文件。如果这是有意的,那么(对于那些将要使用的人)行为是非常奇怪和不清楚的
  • 为什么不用composer autoloader?开始类图。
  • @AlmaDo 否,它将仅包含 __autoload 函数所需的特定文件。
  • @AlmaDo 它将包括两个 foo 类。但是,为什么任何开发人员都会有多个具有相同名称的类?.. 如果这真的成为一个问题,那么 for 循环中总会有一个中断,只包含函数遇到的第一个类。跨度>

标签: php class recursion include include-path


【解决方案1】:

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

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

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

现在采用 Emil 的 答案并稍作改动: (如果文件名类似于上面文件结构中的“Class.php”)

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] =&gt; [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,但对我来说,它似乎比在__autoload() 函数中每次都运行getClasses() 函数更好。

如果其他人有什么要补充的,请随意!我只是尝试了我自己的小方法,它可以正常工作!

注意:

我之前使用的是file_exists(),我认为上述方法是;快很多。

更新

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

所以我做了一些研究,从 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:每个类都必须有唯一的类名/文件名。除非有人可以帮忙修改以允许。

【讨论】:

    【解决方案2】:

    你可以使用 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;
    }
    

    【讨论】:

      猜你喜欢
      • 2021-12-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多