PHP 的 __autoload() 有何独特之处?

发布于 2024-09-28 16:59:50 字数 1745 浏览 4 评论 0原文

PHP 的 __autoload()文档)是我觉得很有趣。它的工作原理如下:

  • 您尝试使用一个类,例如 new Toast_Mitten()(footnote1)
  • 该类尚未加载到内存中。 PHP 收回拳头,用错误来惩罚你。
  • 它暂停了。 “等等,”它说。 “定义了一个 __autoload() 函数。”它运行它。
  • 在该函数中,您以某种方式将字符串 Toast_Mitten 映射到 classes/toast_mitten.php 并告诉它需要该文件。确实如此。
  • 现在该类已在内存中,您的程序将继续运行。

内存优势:您只需加载所需的类。简洁的好处:您可以停止在各处包含如此多的文件,而只需包含您的自动加载器。

那么事情会变得特别有趣

如果1) 您的 __autoload() 具有自动从类名确定文件路径和名称的方法, 。例如,也许您的所有类都在 classes/ 中,而 Toast_Mitten 将在 classes/toast_mitten.php 中。或者您可以将类命名为 Animal_Mammal_Weasel,该类位于 classes/animal/mammal/animal_mammal_weasel.php 中。

2)您使用工厂方法来获取类的实例。

$Mitten = Mitten::factory('toast');

Mitten::factory 方法可以对自己说,“让我们看看,我是否有一个名为 Toast_Mitten() 的子类?如果有,我将返回它;如果没有,我将只返回一个我自己的通用实例 - 一个标准的手套。哦,看!__autoload() 告诉我有一个特殊的 toast 类。”

因此,您可以开始在整个代码中使用通用手套,当有一天您需要 toast 的特殊行为时,您只需创建该类并 bam! - 您的代码正在使用它。

我的问题是双重的:(

  • 事实)其他语言是否有类似的结构?我看到 Ruby 有自动加载,但似乎你必须在给定的脚本中指定您希望在哪些类上使用它。
  • 意见)这也太神奇了吧?如果您最喜欢的语言不能做到这一点,您是否会认为“嘿,太棒了,我们应该拥有它”或“伙计,我很高兴 X 语言没有那么马虎?”

1 我对非英语母语人士表示歉意。这是一个小玩笑。据我所知,不存在“吐司手套”这样的东西。如果有的话,那将是一个用来拿起热面包的手套。也许您在自己的国家有吐司手套?

PHP's __autoload() (documentation) is pretty interesting to me. Here's how it works:

  • You try to use a class, like new Toast_Mitten()(footnote1)
  • The class hasn't been loaded into memory. PHP pulls back its fist to sock you with an error.
  • It pauses. "Wait," it says. "There's an __autoload() function defined." It runs it.
  • In that function, you have somehow mapped the string Toast_Mitten to classes/toast_mitten.php and told it to require that file. It does.
  • Now the class is in memory and your program keeps running.

Memory benefit: you only load the classes you need. Terseness benefit: you can stop including so many files everywhere and just include your autoloader.

Things get particularly interesting if

1) Your __autoload() has an automatic way of determining the file path and name from the class name. For instance, maybe all your classes are in classes/ and Toast_Mitten will be in classes/toast_mitten.php. Or maybe you name classes like Animal_Mammal_Weasel, which will be in classes/animal/mammal/animal_mammal_weasel.php.

2) You use a factory method to get instances of your class.

$Mitten = Mitten::factory('toast');

The Mitten::factory method can say to itself, "let's see, do I have a subclass called Toast_Mitten()? If so, I'll return that; if not, I'll just return a generic instance of myself - a standard mitten. Oh, look! __autoload() tells me there is a special class for toast. OK, here's an instance!"

Therefore, you can start out using a generic mitten throughout your code, and when the day comes that you need special behavior for toast, you just create that class and bam! - your code is using it.

My question is twofold:

  • (Fact) Do other languages have similar constructs? I see that Ruby has an autoload, but it seems that you have to specify in a given script which classes you expect to use it on.
  • (Opinion) Is this too magical? If your favorite language doesn't do this, do you think, "hey nifty, we should have that" or "man I'm glad Language X isn't that sloppy?"

1 My apologies to non-native English speakers. This is a small joke. There is no such thing as a "toast mitten," as far as I know. If there were, it would be a mitten for picking up hot toast. Perhaps you have toast mittens in your own country?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

心清如水 2024-10-05 16:59:50

Ruby 和 PHP 都从 Perl 中的 AUTOLOAD 中获取它。

请注意,AutoLoader 模块是一组常见的帮助程序使用 AUTOLOAD 功能的任务。

Both Ruby and PHP get it from AUTOLOAD in Perl.

Note that the AutoLoader module is a set of helpers for common tasks using the AUTOLOAD functionality.

蘸点软妹酱 2024-10-05 16:59:50
  1. 不要使用__autoload()。这是一个全球的事情,所以根据定义,它有点邪恶。相反,使用 spl_autoload_register() 将另一个自动加载器注册到您的系统。这允许您使用多个自动加载器,这是很常见的做法。
  2. 尊重现有惯例。 命名空间类名的每个部分都是一个目录,因此new MyProject\IO\FileReader();应该在MyProject/IO/FileReader.php中> 文件。
  3. 魔法是邪恶的!

    <块引用>

    Mitten::factory 方法可以对自己说:“让我们看看,我是否有一个名为 Toast_Mitten() 的子类?如果有,我将返回它;如果没有,我将只返回我自己的通用实例- 一个标准的手套。哦,看!__autoload() 告诉我有一个特殊的吐司类。”

    相当棘手的代码,请使用简单而详细的代码:

    <前><代码>尝试{
    $mitten = new ToastMitten();
    // 或 $mitten = Mitten::factory('toast');
    } catch (ClassNotFoundException $cnfe) {
    $mitten = new BaseMitten();
    }

  1. Do not use __autoload(). It's a global thing so, by definition, it's somewhat evil. Instead, use spl_autoload_register() to register yet another autoloader to your system. This allows you to use several autoloaders, what is pretty common practice.
  2. Respect existing conventions. Every part of namespaced class name is a directory, so new MyProject\IO\FileReader(); should be in MyProject/IO/FileReader.php file.
  3. Magic is evil!

    The Mitten::factory method can say to itself, "let's see, do I have a subclass called Toast_Mitten()? If so, I'll return that; if not, I'll just return a generic instance of myself - a standard mitten. Oh, look! __autoload() tells me there is a special class for toast. OK, here's an instance!"

    Rather such tricky code, use simple and verbose one:

    try {
        $mitten = new ToastMitten();
        // or $mitten = Mitten::factory('toast');
    } catch (ClassNotFoundException $cnfe) {
        $mitten = new BaseMitten();
    }
    
半衬遮猫 2024-10-05 16:59:50

我认为这个功能非常方便,而且我在其他地方还没有看到过类似的功能。我在其他地方也不需要这些功能。

I think this feature comes in very handy, and I have not seen any features like it else where. Nor have I needed these features else where.

风吹雪碎 2024-10-05 16:59:50

Java也有类似的东西。它称为 ClassLoader 。可能还有其他语言,但它们坚持一些默认实现。

而且,当我们这样做的时候。如果 __autoload 加载任何类型的符号,而不仅仅是类:常量、函数和类,那就太好了。

Java has something similar. It's called a ClassLoader. Probably other languages too, but they stick with some default implementation.

And, while we're at this. It would have been nice if __autoload loaded any type of symbols, not just classes: constants, functions and classes.

笑咖 2024-10-05 16:59:50

请参阅 Ruby 的 Module#const_missing

我刚刚了解到这一点:Ruby 在模块上有一个名为 const_missing 的方法,如果您调用 Foo::BarBar 就会调用该方法> 尚未在内存中(尽管我认为 Foo 必须在内存中)。

ruby-doc.org 中的此示例展示了一种使用它来实现该模块的自动加载器的方法。事实上,根据 Russ Olsen 的“Eloquent Ruby”(第 21 章,“使用 method_missing 进行灵活的错误处理”,其中还涵盖了 const_missing),Rails 使用它来加载新的 ActiveRecord 模型类。

它之所以能够做到这一点,是因为“约定优于配置”的思维方式:如果您引用一个名为 ToastMitten 的模型,如果它存在,它将位于 app/models/toast_mitten.rb代码>.如果您可以将该模型放在任何您想要的地方,Rails 将不知道在哪里寻找它。即使您没有使用 Rails,这个示例以及我的问题中的第 1 点也显示了遵循约定是多么有用,即使您自己创建了约定。

See Ruby's Module#const_missing

I just learned this: Ruby has a method on Module called const_missing that gets called if you call Foo::Bar and Bar isn't in memory yet (although I suppose that Foo has to be in memory).

This example in ruby-doc.org shows a way to use that to implement an autoloader for that module. This is in fact what Rails uses to load new ActiveRecord model classes, according to "Eloquent Ruby" by Russ Olsen (Chapter 21, "Use method_missing for flexible error handling", which also covers const_missing).

It's able to do this because of the "convention over configuration" mindset: if you reference a model called ToastMitten, if it exists, it will be in app/models/toast_mitten.rb. If you could put that model any place you wanted, Rails wouldn't know where to look for it. Even if you're not using Rails, this example, and point #1 in my question, shows how useful it can be to follow conventions, even if you create them yourself.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文