PHP 的 __autoload() 有何独特之处?
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
toclasses/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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
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.
__autoload()
。这是一个全球的事情,所以根据定义,它有点邪恶。相反,使用spl_autoload_register()
将另一个自动加载器注册到您的系统。这允许您使用多个自动加载器,这是很常见的做法。new MyProject\IO\FileReader();
应该在MyProject/IO/FileReader.php
中> 文件。魔法是邪恶的!
<块引用>
Mitten::factory 方法可以对自己说:“让我们看看,我是否有一个名为 Toast_Mitten() 的子类?如果有,我将返回它;如果没有,我将只返回我自己的通用实例- 一个标准的手套。哦,看!__autoload() 告诉我有一个特殊的吐司类。”
相当棘手的代码,请使用简单而详细的代码:
<前><代码>尝试{
$mitten = new ToastMitten();
// 或 $mitten = Mitten::factory('toast');
} catch (ClassNotFoundException $cnfe) {
$mitten = new BaseMitten();
}
__autoload()
. It's a global thing so, by definition, it's somewhat evil. Instead, usespl_autoload_register()
to register yet another autoloader to your system. This allows you to use several autoloaders, what is pretty common practice.new MyProject\IO\FileReader();
should be inMyProject/IO/FileReader.php
file.Magic is evil!
Rather such tricky code, use simple and verbose one:
我认为这个功能非常方便,而且我在其他地方还没有看到过类似的功能。我在其他地方也不需要这些功能。
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.
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.请参阅 Ruby 的 Module#const_missing
我刚刚了解到这一点:Ruby 在模块上有一个名为
const_missing
的方法,如果您调用Foo::Bar
和Bar
就会调用该方法> 尚未在内存中(尽管我认为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 callFoo::Bar
andBar
isn't in memory yet (although I suppose thatFoo
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 inapp/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.