根据这个
http://perldoc.perl.org/UNIVERSAL.html
我不应该使用UNIVERSAL :: isa()而应该使用$ obj-> isa()或CLASS-> isa().
这意味着要首先找出某些东西是引用,然后引用这个类,我必须这样做
eval { $poss->isa("Class") }
并检查$ @和所有那些gumph,否则
use Scalar::Util 'blessed'; blessed $ref && $ref->isa($class);
我的问题是为什么?UNIVERSAL :: isa有什么问题?这对于以下事情来说更清洁:
my $self = shift if UNIVERSAL::isa($_[0], __PACKAGE__)
要查看是否正在对象上调用此函数.还有一个很好的清洁替代方案,不会因为&符和潜在的长线而变得麻烦吗?
主要问题是,如果UNIVERSAL::isa
直接调用,则绕过任何已超载的类isa
.如果这些类依赖于重载行为(他们可能会这样做,或者他们不会覆盖它),那么这就是一个问题.如果你isa
直接在你的祝福对象上调用,那么isa
在任何一种情况下都会调用正确的方法(如果存在则重载,如果不存在,则调用UNIVERSAL ::).
第二个问题是,UNIVERSAL::isa
只会像其他每次使用一样,在祝福的参考上执行你想要的测试isa
.它对于非祝福引用和简单标量具有不同的行为.因此,不检查是否$ref
有福的示例不是做正确的事情,而是忽略错误条件并使用其UNIVERSAL
替代行为.在某些情况下,这可能会导致细微的错误(例如,如果您的变量包含类的名称).
考虑:
use CGI; my $a = CGI->new(); my $b = "CGI"; print UNIVERSAL::isa($a,"CGI"); # prints 1, $a is a CGI object. print UNIVERSAL::isa($b,"CGI"); # Also prints 1!! Uh-oh!!
因此,总而言之,请勿使用UNIVERSAL::isa
...执行额外的错误检查并isa
直接调用您的对象.
请参阅UNIVERSAL :: isa和UNIVERSAL ::的文档,了解为什么不应该这样做.
简而言之,有一些重要的模块需要覆盖'isa'(例如Test :: MockObject),如果你把它称为函数,你就打破了这个.
我不得不说,my $self = shift if UNIVERSAL::isa($_[0], __PACKAGE__)
对我来说看起来并不是很干净 - 反Perl的倡导者会抱怨线路噪音.:)
要直接回答您的问题,答案就在您链接到的页面的底部,即如果包定义了一个isa
方法,那么UNIVERSAL::isa
直接调用将不会调用package isa
方法.从面向对象的角度来看,这是非常不直观的行为.
这篇文章的其余部分只是关于你为什么要这样做的更多问题.
在上面这样的代码中,特定isa
测试会在什么情况下失败?即,如果它是一个方法,在这种情况下,第一个参数不是包类或其实例?
我问这个是因为我想知道你是否有合理的理由想要测试第一个参数是否是第一个对象.也就是说,你只是试图抓住人们说FooBar::method
而不是FooBar->method
或$foobar->method
?我觉得Perl并不是为那种溺爱而设计的,如果人们错误地使用FooBar::method
它们,它们很快就会发现.
你的旅费可能会改变.
其他人都告诉过你为什么不想使用UNIVERSAL::isa
它,因为当事情超载时它就会破裂isa
.如果他们已经习惯了超载那种非常特殊的方法,你当然希望尊重它.当然,你可以这样写:
if (eval { $foo->isa("thing") }) { # Do thingish things }
因为eval
如果抛出异常则保证返回false,否则返回最后一个值.但这看起来很糟糕,你不应该以有趣的方式编写代码,因为语言需要你.我们真正想要的只是写:
if ( $foo->isa("thing") ) { # Do thingish things }
要做到这一点,我们必须确保它$foo
始终是一个对象.但$foo
可能是字符串,数字,引用,未定义的值或各种奇怪的东西.真可惜,Perl无法将所有东西都变成第一类对象.
哦,等等,它可以......
use autobox; # Everything is now a first class object. use CGI; # Because I know you have it installed. my $x = 5; my $y = CGI->new; print "\$x is a CGI object\n" if $x->isa('CGI'); # This isn't printed. print "\$y is a CGI object\n" if $y->isa('CGI'); # This is!
您可以从CPAN中获取autobox.您也可以将它与词法范围一起使用,因此所有内容都可以作为第一类对象,仅用于您想要使用的文件或块,->isa()
而不会产生额外的麻烦.它也做了很多比我已经介绍了在这个简单的例子更多.