【问题标题】:php search through a directory beginning at endphp搜索从末尾开始的目录
【发布时间】:2015-04-13 19:14:23
【问题描述】:

我有这段 PHP 代码,但之前只写过一个递归函数。我想从一个特定的子目录开始并检查文件是否存在。如果它在目录中不存在,我想检查文件的父文件夹,然后递归地继续,直到我找不到文件并返回“”或找到文件并返回其内容。这是我的功能:

/**
*   Recursive function to get sidebar from path and look up tree until we either
*   find it or return blank.
*/
class MyClass{
    public function findSidebarFromPath($path){
        if(file_exists($_SERVER["DOCUMENT_ROOT"].implode("/", $path)."/sidebar.html")){
            return file_get_contents($_SERVER["DOCUMENT_ROOT"].implode("/", $path)."/sidebar.html");
        } else {
            if(count($path) > 0){
                # pop element off end of array.
                $discard = array_pop($path);
                $this->findSidebarFromPath($path);
            } else {
                return "";
            }
        }
    }
}

所以当我调用它时,我会这样做:

$myclass = new MyClass();
$myclass->findSidebarFromPath(array("segment1", "segment2", "segment3"));

假设我要查找的文件位于名为“segment2”的目录中。该函数永远找不到它。 array_pop 函数不会弹出数组末尾的元素,然后调用 findSidebarFromPath 函数。

【问题讨论】:

  • 这不是递归代码,因为您不会在任何地方调用findSidebarFromPath()。您只需致电getSidebar(),您根本没有显示。
  • 内部if分支不返回。
  • 我重命名了发帖功能。对于那个很抱歉。现在应该更有意义了...$this->findSidebarFromPath($path);是我的意思。
  • 哎呀。我只是回答了我自己的问题。现在它起作用了。现在我为提出这个问题感到羞耻:(
  • @BryanC 每个人都会犯错,不要不好意思问问题。另外,你学会了如何以不同的方式解决同样的问题。这总是一个优点。

标签: php recursion


【解决方案1】:

如果你把它写成一个独立的函数,它可能在其他领域对你更有用。在了解了它的工作原理后,我们将向您展示如何将公共函数添加到可以使用它的类中。

/**
 * @param $root string - the shallowest path to search in
 * @param $path string - the deepest path to search; this gets appended to $root
 * @param $filename string - the file to search for
 * @return mixed - string file contents or false if no file is found
 */
function findFile($root, $path, $filename) {
  // create auxiliary function that takes args in format we want
  $findFileAux = function($cwd, $filename) use (&$findFileAux, $root) {
    // resolve the complete filename
    $file = "{$cwd}/{$filename}";
    // if the file exists, return the contents
    if (file_exists($file)) return file_get_contents($file);
    // if the cwd has already reached the root, do not go up a directory; return false instead
    if ($cwd === $root) return false;
    // otherwise check the above directory
    return $findFileAux(dirname($cwd), $filename);
  };
  // starting checking for the file at the deepest segment
  return $findFileAux("{$root}/{$path}", $filename);
}

检查ideone 上的示例输出。


所以这里是如何使用它

findFile($_SERVER["DOCUMENT_ROOT"], "foo/bar/qux", "sidebar.html");

以下是您将它与您的班级整合的方式。请注意,此公共函数与您的原始代码具有相同的 API

class MyClass {
  /**
   * @param $path array - path segments to search in
   * @return mixed - string file contents or false if sidebar is not found
   */
  public function findSidebarFromPath($path) {
    // Here we call upon the function we wrote above
    // making sure to `join` the path segments into a string
    return findFile($_SERVER["DOCUMENT_ROOT"], join("/", $path), "sidebar.html";
  }
}

补充说明

如果$_SERVER["DOCUMENT_ROOT"]/var/www...

  1. 检查/var/www/foo/bar/qux/sidebar.html,如果存在则返回
  2. 检查/var/www/foo/bar/sidebar.html,如果存在则返回
  3. 检查/var/www/foo/sidebar.html,如果存在则返回
  4. 检查/var/www/sidebar.html,如果存在则返回
  5. 因为我们到达了根目录 (/var/www),所以不会进行进一步的搜索
  6. 如果 sidebar.html 在上述任何地方都不存在,则返回 false

这是去掉了解释性 cmets 的相同函数

/**
 * @param $root string - the shallowest path to search in
 * @param $path string - the deepest path to search; this gets appended to $root
 * @param $filename string - the file to search for
 * @return mixed - string file contents or false if no file is found
 */
function findFile($root, $path, $filename) {
  $findFileAux = function($cwd, $filename) use (&$findFileAux, $root) {
    $file = "{$cwd}/{$filename}";
    if (file_exists($file)) return file_get_contents($file);
    if ($cwd === $root) return false;
    return $findFileAux(dirname($cwd), $filename);
  };
  return $findFileAux("{$root}/{$path}", $filename);
}

您可能还想考虑使用DIRECTORY_SEPARATOR 而不是硬编码的"/",以便可以在各种平台上可靠地使用此代码。

【讨论】:

  • 目录路径:$path在这个函数中是如何减少的?
  • @BryanC。在辅助函数的最后一行可以看到dirname($cwd)调用
  • 随意使用“/”作为“windows”上的目录分隔符——它工作正常。它引起麻烦的唯一地方是 CLI,除非在引号中使用。这是由于使用“/”的“开关”。我认为信息太多。
  • 哇。我什至不知道 PHP 命名空间。我想我还有很多东西要学。
  • @BryanC。我怀疑您偶然发现了命名空间,因为您在我的代码中看到了use。这里的use 与 PHP 命名空间无关。我正在使用use 从父作用域继承变量以用于anonymous function
猜你喜欢
  • 1970-01-01
  • 2016-10-02
  • 2011-01-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多