【问题标题】:PHP Class AutoloadingPHP 类自动加载
【发布时间】:2014-04-26 15:06:16
【问题描述】:

我有一个“简单框架”,它的主要实例是 $app。现在,实现自动加载器的最佳方法是什么(不使用 Composer)。我需要的是有一个类来处理所有的自动加载(支持各种命名空间)。我有一些方法/困境。

起初我认为我应该创建一个处理所有事情的“静态”类。但后来我想到了一些事情。如果我在实例化 $app(包含所有路径)之前使用自动加载器,我需要在 $app 之外定义路径。而且,如果在自动加载类时发生错误,我将无法正确处理错误(错误处理程序在 $app 内,并在之后实例化)。

然后我想到了依赖注入,使自动加载器成为应用程序内部的对象。这将解决错误处理问题,并且不需要我对路径进行硬编码或将它们设为全局。但在实例化自动加载器之前,我还必须加载许多类(包括 $app)。

但由于这个问题,我真的陷入了痛苦的世界,我真的不知道从哪里开始,有什么我应该考虑的建议吗?你能解释一下我应该使用哪种方法以及为什么?

谢谢。

【问题讨论】:

  • 您的 index.php(入口点)创建 App 的实例。在 App->__construct 中,您在需要自动加载类的任何内容之前创建自动加载器实例。
  • Autoloader 应该与您的框架、应用程序和其他类似的东西分开。为什么不想使用 Composer?为什么要将所有内容都放入 $app 实例中?
  • @TomaszKowalczyk 我明白了,所以它不应该知道应用程序是如何工作的,并尊重 LoD。据我从您的评论中了解到,包括框架内的自动加载器应该是没有问题的。假设“用户”扩展了框架并希望自动加载他的类,我将如何解决这个问题?另外,如何在不处理框架错误的情况下解决缺少类的问题?而且,不是我不想使用 Composer(这很简单),而是我想这样做是为了学习。
  • SPL 自动加载器堆栈,因此自动加载器没有理由提前知道自动加载器需要执行的所有操作。它可以稍后添加到堆栈中

标签: php autoload


【解决方案1】:

根据我在这个问题中得到的提示,我进行了更多搜索,找到了可以学习的好资源。

什么是自动加载?

自动加载基本上是程序找到未知类名并尝试在未定义类名的情况下加载它的过程。如果没有自动加载器,此行为将导致致命错误(至少对于 PHP)。使用自动加载器,情况会发生变化,程序将尝试加载类名,但不知道在哪里可以找到它,但依赖于为此目的考虑的函数或类,这些函数/类称为自动加载器

__autoload() 与 spl_autoload_register()

在 PHP 中,我们有两种不同的方式来实现自动加载(您可能会发现从PHP's site 阅读它很有用。)。第一个是旧的__autoload(),最新的是spl_autoload_register()。但究竟有什么区别?基本上 __autoload() 是独一无二的,拥有多个自动加载器会给你带来很多麻烦,并且会让你解决一个可以通过使用最新的 spl_autoload_* 函数轻松避免的问题。另一方面,spl_autoload_register() 允许程序通过将多个 Autoloaders 放入堆栈中来拥有多个 Autoloader,这样整个系统变得更加灵活且简单得多(具有单个 Autoloader 用于不同目的的结果在拥有处理许多请求的大型独特函数中,这样您的代码可维护性和可重用性就会降低)。 警告:使用 spl_autoload_register() 会覆盖 __autoload(),所以要小心。

编码标准(PHP 中):PSR-0 与 PSR-4

首先让我们说PSR-4 较新,它被认为是PSR-0 的改进,但不是强制性的,您必须使用 4 而不是 0,因为标准 (PSR-4) 规定:

它是完全可互操作的,并且可以与任何其他自动加载规范一起使用,包括 PSR-0。

那么我为什么要使用一个而不是另一个呢?

现在这取决于您,但作为建议,PSR-4 解决了 PSR-0 的“嵌套”问题,因此您应该使用前者。假设我有一个应用程序,并且我的应用程序依赖于外部组件,PSR-0 遵循以下语法:

\vendor\(sub_namespaces\)class_name

sub_namespaces 可能不存在的地方。但这会转化为硬盘驱动器上的完全限定路径:

path/to/project/vendor/sub/namespaces/class/name.php

现在假设我想在我的应用程序中包含一个名为 YourLibrary 的库

\YourDeveloper\YourLibrary\YourFunction

这将转化为

/path/to/project/YourDeveloper/YourLibrary/YourFunction

问题来了,如果我想将该库放在我的子文件夹中怎么办:

/path/to/project/vendor/vendor_name

PSR-0 是绝对的,你不能只修改命名空间来控制这种行为(这会很愚蠢并且需要太多时间)所以它会转化为:

/path/to/project/vendor/YourDeveloper/src/YourDeveloper/YourLibrary/YourFunction

这不是非常嵌套和冗余吗?好吧,使用 PSR-4 你可以避免这种情况并将其转换为

/path/to/project/vendor/YourDeveloper/YourLibrary/YourFunction

无需更改命名空间或自动加载器。这基本上就是 PSR-4 的工作原理。这个解释很简短,但它让您了解 PSR-4 诞生的原因以及您应该使用它的原因。如果你需要更充分的解释,你可以去阅读 PSR-0/4 规范或者你可以阅读thissitepoint 上的漂亮文章。

我真的应该关心标准吗?

如果您已经在编程领域工作了足够长的时间,您可能最终不会问这样的问题。但如果你是,你可能是一个新程序员,或者你做程序员的时间不够长,这就是你应该阅读这个答案的原因。 在 IT 世界,尤其是在编程领域,标准几乎就是一切。如果我们不遵循标准,我们的计算机上甚至可能没有视频。如果任何人都遵循自己的标准,那么一切都会显得一团糟,在这种情况下,自动装载机将变得个人化;因此,您最终将拥有许多 Autoloader,而不是一个简单的 Autoloader,每个标准一个,这使您的应用程序更难以维护和调试(因为每个人都可以制造错误)。

【讨论】:

    【解决方案2】:

    如果您编写一个框架,您应该始终查看现有的框架,它们已经正确地解决了您的问题。然后您会受到启发或只是使用该组件。一个很好的起点是 symfony,它们的组件是分离和测试的。如果您使用作曲家加载它或手动下载它是您的选择;)

    他们还有一个 Classloader http://symfony.com/doc/2.0/components/class_loader.html,您可以将其用作它。或者你看看他们的方法是什么。

    自动加载器(或您的类加载器)应该包含在应用程序的开头,并且这应该是您直接包含的唯一类。

    如果你想加载你的类动态,你必须看看你是如何存储你的类的,有不同的“标准”方式,比如 PSR0 http://www.php-fig.org/psr/psr-0/。如果您希望您的用户添加他们自己的类,那么当他们使用您的框架时,您应该考虑支持多种标准。

    【讨论】:

    • 我已经知道 psr-0 或 psr-4,但感谢您指出一个好的(旧的)方法和 symfony 类加载器。 ;)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-20
    • 2013-05-26
    • 1970-01-01
    • 2014-08-15
    • 2016-05-06
    • 2020-11-03
    相关资源
    最近更新 更多