【问题标题】:Class not found when successfully included成功包含时找不到类
【发布时间】:2017-11-25 18:07:42
【问题描述】:

我因为找不到类而收到此致命错误:

致命错误:未捕获的错误:找不到类“HomeController”

但文件已包含在内。

require_once self::CONTROLLERS_PATH . $this->controller . '.php';
var_dump(file_exists(self::CONTROLLERS_PATH . $this->controller . '.php'));
new $this->controller;

我通过返回 true 的 var_dumping file_exists 对其进行了调试。我检查了命名空间,一切看起来都很好。如果我 var dump $this->controller,它的值是预期的 - string(14) "HomeController"。如果我像new HomeController(); 那样对其进行硬编码,则该类被初始化。但是,为什么它不能从变量中工作?你可以在下面看到我的代码。这是我的文件结构:

App.php

<?php


namespace App\Core;

class App
{
    protected $controller = 'HomeController';
    protected $method = 'index';
    protected $params = [];

    const CONTROLLERS_PATH = '../App/Controllers/';

    public function __construct ()
    {
        $url = $this->parseUrl();

        if(file_exists(self::CONTROLLERS_PATH . ucfirst($url[0]) . '.php'))
        {
            $this->controller = ucfirst($url[0]); //Update $this->controller value
            unset($url[0]);
            echo 'file exists';
        }
        require_once self::CONTROLLERS_PATH . $this->controller . '.php';
        var_dump(file_exists(self::CONTROLLERS_PATH . $this->controller . '.php'));
        var_dump($this->controller);
        new $this->controller;

        if(isset($url[1]))
        {
            if(method_exists($this->controller, $url[1]))
            {
                $this->method = $url[1];
                unset($url[1]);
                echo 'method exists';
            }
        }

        $this->params = $url ? array_values($url): [];
        call_user_func_array([$this->controller, $this->method], $this->params);
        var_dump($url);
    }

    public function parseUrl()
    {
        if(isset($_GET['url']))
        {
            return $url = explode('/', filter_var(rtrim($_GET['url'], '/'), FILTER_SANITIZE_URL));
        }
    }
}

HomeController.php

<?php

namespace App\Controllers;

    class HomeController
    {
        public function index()
        {
            echo 'asd';
        }
    }

【问题讨论】:

  • 它可能是命名空间吗? (即使它和这个脚本是同一个命名空间)
  • 我不明白你的意思。
  • 我强烈建议你只使用作曲家自动加载,而不是自己组装解决方案
  • 啊,对不起,忘了你必须先把它全部放到一个var中:$className = "\\App\\Controllers\\".$this-&gt;controller;然后new $className;
  • 那我就把它写成答案

标签: php


【解决方案1】:

当通过变量名实例化一个类时,您总是必须包含整个命名空间。这必须首先存储为字符串。
一个例子:

namespace Api;

Class test {

    public function __construct() {
        echo "test";
    }
}

$className = 'test';
$classNameNamespaced = "\\Api\\".$className;

$a = new $classNameNamespaced;  // echoes "test"

在你的情况下:

$className = "\\App\\Controllers\\".$this->controller;
new $className;

【讨论】:

    【解决方案2】:

    因为代码在命名空间中,所以new $this-&gt;controllernew HomeController 不同,即使$this-&gt;controller 的值是HomeController

    表达式new HomeController 在编译时被评估,并且由于命名空间,它被扩展为new \App\Controllers\HomeControllerName resolution rules 上的规则#6)。解释器需要完全限定的类名才能找到它。

    表达式new $this-&gt;controller 在运行时被求值,它导致new HomeControllernew \HomeController 相同。根命名空间中没有定义任何类HomeController,因此您得到了错误。

    您可以通过将完整的类名构建到字符串中来使其轻松工作:

    $class = 'App\\Controllers\\'.$this->controller;
    new $class;
    

    在文档页面"Namespaces and dynamic language features" 中查找更多示例。

    但加载类的最佳方式是使用autoloader generated by Composer

    【讨论】:

    • 不需要在命名空间的开头有一个 `\` 吗?因为我们已经在一个命名空间中了..
    • 命名空间只存在于代码中。在编译期间,所有对象名称都扩展为完全限定名称。在运行时没有命名空间,名称也不会扩展。您在变量中作为字符串的任何名称都被视为完全限定名称,它是否以反斜杠开头都没有关系。查看Namespaces and dynamic language features 文档页面上的示例#2。
    猜你喜欢
    • 2016-04-28
    • 1970-01-01
    • 2019-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-28
    • 1970-01-01
    • 2014-05-25
    相关资源
    最近更新 更多