【问题标题】:Cannot find Class with PHP Namespace找不到带有 PHP 命名空间的类
【发布时间】:2012-01-26 11:58:46
【问题描述】:

我之前发布了一些关于在 PHP 中使用命名空间的问题,从我得到的信息来看,我下面的这个示例代码应该可以工作。

但是,当我尝试像这样在 PHP 中使用命名空间时出现错误。这是按原样运行下面的代码时的第一个错误...

Fatal error: Class 'Controller' not found in E:\Controllers\testing.php on line 6

E:\Controller\testing.php 文件

<?php
use \Controller;

include('testcontroller.php');

$controller = new Controller;
$controller->show();
?>

E:\Controller\testcontroller.php 文件

<?php
use \Library\Registry;

namespace Controller
{
    class Controller
    {
        public $registry;

        function __construct()
        {
            include('E:\Library\Registry.class.php');
            $this->registry = new Registry;
        }

        function show()
        {
            echo $this->registry;
            echo '<br>Registry was ran inside testcontroller.php<br>';
        }
    }
}
?>

E:\Library\Registry.class.php 文件

<?php
namespace Library\Registry
{
    class Registry
    {
        function __construct()
        {
            return 'Registry.class.php Constructor was ran';
        }
    }
}
?>

如您所见,我试图使其尽可能简单,只是为了让命名空间部分正常工作。我尝试了不同的变体,但似乎无法弄清楚。

【问题讨论】:

    标签: php namespaces


    【解决方案1】:

    当你将一个类 Controller 放在命名空间 Controller 中时,你必须这样引用它:

    $controller = new Controller\Controller();
    

    \Controller 将是全局(默认)命名空间中的一个类,即好像您根本没有使用任何命名空间。

    【讨论】:

    • 不要因为use Controller;声明而认为你需要这样做
    • @Cassy 是的,这就是我使用use Controller; 的原因,所以希望我不必使用那种更丑陋的方法
    • @Casey 我还是尝试了它只是想看看会发生什么,它把错误改成了Fatal error: Class 'Controller\Registry'
    • 这是因为您在全局命名空间中引用 Registry,而不是在使用它的命名空间中。您的课程实际上也称为 Library\Registry\Registry
    • @Dan,将$this-&gt;registry = new Registry; 更改为new \Library\Registry\Registry 实际上确实消除了错误。必须有一种方法来做我想做的事情,你知道吗? use 的全部意义在于避免这种情况
    【解决方案2】:

    试试

    <?php
    use \Library\Registry;
    
    namespace Controller;
    class Controller
    {
        public $registry;
        function __construct()
        {
            include('E:\Library\Registry.class.php');
            $this->registry = new Registry;
        }
        function show()
        {
            echo $this->registry;
            echo '<br>Registry was ran inside testcontroller.php<br>';
        }
    }
    ?>
    

    <?php
    namespace Library\Registry;
    class Registry
    {
        function __construct()
        {
            return 'Registry.class.php Constructor was ran';
        }
    }
    ?>
    

    【讨论】:

      【解决方案3】:

      奇怪的是,我发现在上面问题的示例代码中,如果我将所有定义为 MyLibraryNamespace's 更改为类似 MyLibrary 的东西,那么它会像下面的代码......

      E:\Library\Registry.class.php 文件

      <?php
      namespace MyLibrary
      {
          class Registry
          {
              function __construct()
              {
                  echo 'Registry.class.php Constructor was ran';
              }
          }
      }
      ?>
      

      然后当我在另一个文件中使用use MyLibrary\Registry; 时,我可以按照我的计划访问它...

      $this->registry = new Registry;
      

      这对我来说很奇怪的原因是这现在使类名看起来也是Namespace。所以我不需要将命名空间设置为“MyLibrary\Library”来访问Registry,而是像我在这个答案中展示的那样,只需调用类的名称就可以访问它。

      我希望这是有道理的并对其他人有所帮助。我不会接受这个作为答案,因为我希望有更多专业知识的人会进来并发布一个更好的答案和解释

      【讨论】:

        【解决方案4】:

        像类一样命名命名空间并不是一个好主意,因为它令人困惑(我认为这就是这里发生的情况)。此刻,您通过 use Controller 定义别名,这引用类 \Controller 或命名空间 \Controller,但您的类,因为它在命名空间内,所以命名为 \Controller\Controller 1

        use Controller;
        $class = new Controller\Controller;
        

        $class = new \Controller\Controller;
        

        use Controller\Controller;
        $class = new Controller;
        

        这个想法是,当您尝试使用其相对名称访问一个类时,它会尝试将“第一部分”映射到使用use 定义的任何别名(请记住use MyClassuse MyClass as MyClass 相同。 as 后面的东西是别名)。

        namespace MyNamespace\MyPackage\SomeComponent\And\So\On {
          class MyClass {}
        }
        namespace Another {
          use MyNamespace\MyPackage\SomeComponent; // as SomeComponent
          $class =              new SomeComponent\An\So\On\MyClass;
        }
        

        如您所见,PHP 发现 SomeComponent 作为第一部分,并将其映射到上面一行的 SomeComponent-alias。

        您可以在manual about namespaces 中了解更多信息。

        1 它称为“全限定类名”,如果你用它的完整名称命名一个类。

        【讨论】:

          【解决方案5】:

          即使使用use 语句,您也需要指定您尝试实例化的类的命名空间。这里有很多例子:http://www.php.net/manual/en/language.namespaces.importing.php

          为了更好地理解它,我将向您描述它是如何工作的。在您的情况下,当您执行 use \Controller 时,整个 Controller 命名空间对您可用,但此命名空间中的类不可用。所以,例如:

          <?php
          include('testcontroller.php');
          
          use \Controller;
          
          // Desired class is in namespace!
          $controller = new Controller\Controller();
          
          // Error, because in current scope there is no such class
          $controller = new Controller();
          
          $controller->show();
          ?>
          

          另一个例子:

          testcontoller.php:

          <?php
          namespace Some\Path\To\Controller;
          
          class Controller
          {
              function __construct()
              {
          
              }
          
              function show()
              {
                  echo '<br>Was run inside testcontroller.php<br>';
              }
          }
          ?>
          

          testing.php:

          <?php
          include('testcontroller.php');
          
          use \Some\Path\To\Controller;
          
          // We now can access Controller using only Controller namespace,
          // not Some\Path\To\Controller
          $controller = new Controller\Controller();
          
          // Error, because, again, in current scope there is no such class
          $controller = new Controller();
          
          $controller->show();
          ?>
          

          如果您希望准确导入Controller ,您需要执行use Controller\Controller - 然后该类将在您当前的范围内可访问。

          【讨论】:

          • 很好的例子,我昨晚想通了,但你可以描述一下。所以我想我最好把我所有的Library classes 放到像Library 这样的同一个命名空间中,然后在上面的测试控制器上,我可以为我在那个控制器中需要的库中的每个类使用use Library\Classname,这样我就可以然后像new Registry 这样评估他们...在php.net/manual/en/language.namespaces.importing.php 上我认为这是在说这是importing a global class 所以我不确定这是否是一个坏主意
          • 我试图限制每个类的依赖,这就是为什么对我来说使用类的完整限定名并不难。
          • 错了:使用use,您还可以为具体类定义别名。在示例中use \Controller; new Controller; 不是很明显,但您可以尝试use Vendor\Package\Component\Controller; new Controller。我的意思是:这是错误的,您需要在每种情况下定义一个类的命名空间。请参阅 jasondeavis 评论中的链接。它描述了 PHP 如何解析相关类名。
          • 阅读我的全部评论。特别是,“如果您希望准确导入 Controller 类,则需要执行 use Controller\Controller,然后,该类将可以在您当前的范围内访问。”部分。
          • 我只是困惑,为什么包含('testcontroller.php');当您已经使用 \Some\Path\To\Controller 导入类时;?
          猜你喜欢
          • 1970-01-01
          • 2017-05-01
          • 1970-01-01
          • 2016-08-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-10-04
          相关资源
          最近更新 更多