为什么我们使用 Catalyst 的上下文对象?它的目的是什么?
我在想我真的不明白为什么催化剂中的几乎所有内容都使用上下文对象。似乎一切都是从
my ( $self, $c ) = @_;
我们用催化剂模型包装 DBIC 开始的,最后
$c->model('DBIC::Table') ...
可能是我们这样做
$c->log->warn('foo');
,但我不明白为什么我们不直接做
log('warn', 'foo'); # or whatever the API for some log library is.
为什么我们通过上下文对象做所有事情?它有何特别之处?
I was thinking that I don't really understand why just about everything in catalyst uses the context object. Seems that just about everything starts with
my ( $self, $c ) = @_;
we wrap DBIC with a catalyst model and end up with
$c->model('DBIC::Table') ...
or maybe we do
$c->log->warn('foo');
but I don't understand why don't we just do
log('warn', 'foo'); # or whatever the API for some log library is.
Why do we do everything though the context object? what makes it special?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
如果我正确理解发生了什么(并且我没有仔细研究催化剂,所以这很容易实现),上下文变量就是调用框架。当请求到来时,框架将所有信息构建到自身中,并调用类中传递自身的方法,以便您的方法可以访问所有这些信息和框架的其余部分。您可能会发现阅读控制反转(或 IoC)有助于您理解。
此外,通过将所有功能包装在上下文变量中,您不会遇到任何命名空间问题。控制器、模型等类只需具有它们在名称空间中声明的方法。
If I understand what is going on correctly (and I haven't looked at catalyst very hard, so that is easily possible), The context variable is the calling framework. When a request comes in, the framework builds all of the information into itself and the calls a method in your class passing itself along so your method has access to all of that information and the rest of the framework. You may find that reading about inversion of control (or IoC) helps you understand.
Also, by wrapping up all of the functionality in a context variable, you don't run into any namespace issues. Controller, model, etc. classes only have to have the methods they declare in their namespace.
Perl 和其他语言中的一个常见习惯用法是传递有效地提供命名空间接口的“上帝”对象。这允许调用方法,而不需要将所有函数导入到您的命名空间中。这些命名空间中的每一个都可以使用不同的运行时数据(对象的实例)进行自定义。
如果您不喜欢在对象上调用方法的语法,那么听起来您正在寻找类似于 Javascript 的
with
块的东西。虽然 Perl 没有执行此操作的本机结构,但它确实提供了制作此结构的工具:给定模拟对象:
然后您可以编写:
哪个打印:
玩得开心,只需记住内置名称或已定义子例程的名称不会在
with
块中被覆盖。您可以使用名称的ucfirst
版本,或者仅在这些实例中调用该方法。with
块中的所有新子例程也必须使用括号Log('hello')
调用,而不是Log 'hello'
因为名称在编译时是未知的。A common idiom in Perl and other languages is to pass around "god" objects that effectively provide an interface to a namespace. This enables calling methods instead of requiring all of the functions to be imported into your namespace. Each of these namespaces can also be customized with different runtime data (instances of the object).
If you don't like the syntax of calling methods on the object, it sounds like what you are looking for is something similar to Javascript's
with
block. While Perl does not have a native structure that does this, it does provide the tools to make one:Given the mock object:
You can then write:
Which prints:
Have fun, just keep in mind that builtin names or names of already defined subroutines will not be overridden in the
with
block. You can use theucfirst
version of the name or just call the method in those instances. All the new subroutines in thewith
block must also be called with parensLog('hello')
and notLog 'hello'
since the name is not known at compile time.通常有人会编写您在 Catalyst::Controller 中显示的所有内容。现在您必须记住 Catalyst 控制器的存在是为了进行 URL 映射。当然,可以在控制器中导入很多函数,但是当Catalyst本身导入一个
log
函数时,如何使用这个函数进行URL映射呢?例如
子日志:Local { ... }
。很快这将是不可能的,或者它会比应有的更加复杂。一个Controller几乎没有任何函数,这样你就不需要记住很多函数,也不会有任何冲突。这与 Perl 本身选择在特殊变量中使用特殊字符的原因相同。如
$/
、$_
、$]
等。当然,他们也可以使用$INPUT_RECORD_SEPARATOR
或$RS
作为默认值,但是您需要了解它们,如果您不知道,它可能会与您的代码发生冲突所有特殊变量。另一个原因是您在
$c
上调用的附加功能有一些上下文。例如,您可以使用$c->log->disable('warn', 'error')
启用或禁用日志记录,或者仅启用它们。此上下文已正确传递到更深层的控制器中。而且它们不是全局的,您可以根据对另一个状态的每个请求来设置它们。另一个原因是,您使用的额外功能有时可能需要读取配置文件或其他内容。使用为每个请求传递的对象(每个
$c
对于每个请求都是特殊的)并且可以为每个请求进行修改,使您的扩展能够从应用程序请求信息或处理状态一个具体的请求。但如果您仍然不希望这样做,则不必强制您使用
$c
。例如,您可以手动加载 Log::Log4Perl,并为其使用特殊配置,而根本不使用$c->log
。或者你可以自己导入很多函数。但我认为默认不污染名称空间并让您可以为每个请求做一些特殊的事情是一个很好的默认设置。至少没有规定必须使用
$c
。例如,我自己直接使用 DateTime 并创建新对象,而不使用允许我执行$c->datetime
的 Catalyst::Plugin::DateTime。而且我认为最后一项没有任何好处。仅仅因为存在很多扩展$c
的插件,并不意味着它们有用或者您必须使用它们。Someone would typically write everything what you have shown in a Catalyst::Controller. Now you must remember that a Catalyst Controller exists to do your URL mapping. Sure, it is possible to import a lot of functions into the controller, but when Catalyst itself import a
log
function, how do you use this function for URL mapping?For example
sub log : Local { ... }
. Shortly that would not be possible, or it will be more complex then it should be. A Controller have nearly no Functions, so that you don't need to remember a lot of functions and don't have any conflicts.Its the same reason why Perl itself choose to have special characters in special variables. Like
$/
,$_
,$]
and so on. Sure they could also use$INPUT_RECORD_SEPARATOR
or$RS
as the default, but then you need to knew them, and it probably can conflict with your code if you don't knew all special variables.Another reason is that your additional features you call on
$c
have some context. For example you can enable or disable logging with$c->log->disable('warn', 'error')
or just enable them. This context is correctly passed into deeper controller. And they are not global, you can set them on every request to another state.Another reasons is, that extra functionality that you use can and sometimes need to read the configuration file or other things. Using a object that you pass around for every request (Every
$c
is special for every request) and can modified for every request gives your extension the possibility to request information from your application or to handle a state for a specific request.But if you still don't want this, you are not forced to use
$c
. For example you can just load Log::Log4Perl manually, and use a special config for it, and not use$c->log
at all. Or you can import a lot of functions by yourself. But i think the default to not pollute the namespace and give you the possibility to do something special for every request is a good default.And at least there is no rule that you must use
$c
. For example, i myself use DateTime directly and create new objects and don't use Catalyst::Plugin::DateTime that allows me to do$c->datetime
. And i don't see any benefit of doing the last. Just because there exists a lot of plugins that extends$c
, does not mean they are useful or you must use them.