PHP类名与变量名和命名空间


PHP Class name with variable name and namespace

我正在使用PHP5构建我自己的MVC框架。我有一种情况,我所有的控制器都在Controller命名空间中,如:

namespace Controllers
{
    class Home extends 'Framework'Core'Controller 
    {
        ...
     }
}

在应用程序逻辑中,我需要从调用传递的URL中选择要调用哪个控制器,如下所示:

namespace Framework'Core;
class Application 
{
     protected $controllerName = 'home';
     protected $methodName = 'index';
     protected $controller;
     public function __construct()
     {
          // Parse the received  URL
          $url = parseUrl();
          // Choose the controller, if file exists
          if (file_exists('../app/controllers/' . $url[0] . '.php'))
          {
              $this->controllerName = $url[0];
              unset($url[0]);
          }
          require_once '../app/controllers/' . $this->controllerName . '.php';
          // Call the controller
          $objToCall = '''Controllers''' . $this->controllerName;
          $this->controller = new $objToCall(); <<<======= PROBLEM HERE
          ... Proceed choosing the method and calling the objects method....
          }
    }
}
我的问题是:

我的控制器文件叫做home.php,我的类叫做Home(首字母大写)。所以上面的代码找不到/Controllers/home类,因为类是/Controllers/Home

另一方面,如果我从控制器中删除命名空间并调用:
$this->controller = new $this->controllerName;

它工作正常,即使名称是home ....

我的问题:

a)如果我没有涉及到命名空间,为什么home被翻译为home ?

b)如何解决从命名空间调用类而不需要知道其大写/小写条件的问题?

请不要建议将第一个字母改为大写,因为我可能有客户收据,个人提现等类。

谢谢你的帮助。

你能做的就是创建一个数组来匹配文件和类。

  1. 读取/controllers/文件夹中的所有文件
  2. 创建一个关联数组,将文件的小写版本与实际格式
  3. 匹配
  4. 使用这个关联数组来获得正确的文件,而不必担心大小写。

例如,如果你的文件夹包含:

  • home。
  • RecipeForDisaster.php
  • AnotherController.php

关联数组将包含:

Key                   Value
--------------------  ----------------------------
home                  Home.php
recipefordisaster     RecipeForDisaster.php
anothercontroller     AnotherController.php

通过构建这种数组,可以将类(无论其大小写)与文件匹配。

灾难配方

这将达到你想要的,但在我看来,这是一个灾难的配方。为什么?因为在某些操作系统(Linux, OSX,…)中,您可以将home.phpHome.php放在同一个文件夹中。你怎么知道要用什么文件呢?提供的解决方案将不起作用,因为很明显,同一个键不能有两个值。

你要考虑的另一件事是PHP中的类是不区分大小写的。这就是名称空间如此重要的原因。这意味着下面的代码可以完美地工作:

class myclass {
    public function printme() {
        print 'hello world';
    }
}
$a = new myclass();     // Correct case
$a->printme();
$b = new MyClass();     // "Incorrect" case... but still working
$b->printme();

建议解决方案

我真的认为你应该将类名大小写与文件匹配。这样,您将避免潜在的冲突,并确保不会错误地将类映射到错误的文件。

我不是建议你把的第一个字母改成大写,我是建议你严格使用类提供的大小写来找到正确的路径。

开发人员应该知道:如果你输入的类名不正确(意思是不考虑大小写),你就不能指望自动加载器能正常工作。

路由

大多数框架都可以自动路由,但也提供了手动路由的可能性。你可以添加一个路由模块,允许开发人员"覆盖"默认路由。通过这样做,你会取悦那些想要尊重你的标准和那些想要按照他们的方式去做的人。

结论

你的问题似乎很简单。但是,事实上,如果你想让它灵活,避免过于严格,你需要考虑很多事情。

你也可以像这样混合这个答案中提供的策略:

  1. 检查文件是否与用户输入的文件完全相同。如果它存在,就使用它。
  2. 检查类名的小写版本是否存在。如果它存在,就使用它。
  3. 浏览文件夹,并通过找到一个"看起来像"类名的文件(不考虑大小写)来尝试一个神奇的映射。
问题仍然是:你希望是灵活的吗?你的电话…

这就是路由的目的。如果没有正确的根,你将很难解决这个问题。我现在唯一能想到的是让控制器只由一个单词组成,并在URL段上使用ucfirst()。(这实际上是我在自己的框架中选择的方式,因为它是最快的,要求最低的)

所以回答你的问题:

a)这取决于服务器运行的系统类型。在windows的情况下没有关系,在linux上,所以你必须记住这一点。至于为什么它的行为方式-显然类在PHP是不区分大小写的。(由Maxime回答)

b)你可以通过使用适当的路由或简单的控制器类名来解决这个问题。或者,当用户不需要输入URL时,您可以使用URL中字母的正确大小写。还有一个选项是用小写的文件名,但是这样你就造成了不一致,如果有一天你决定实现自动加载,可能会给你带来麻烦,所以这是一个坏主意,但仍然是一种可能性。

此外,我也一直在创建自己的框架,如果你感兴趣的话,我可以给你一些其他的提示。