本主题扩展了什么时候/我应该在PHP中使用__construct(),__ get(),__ set()和__call()? 其中谈到了__construct,__get和__set魔术方法.
从PHP 5.3开始,有一个新的魔术方法叫做__invoke.__invoke当脚本尝试将对象作为函数调用时,将调用该方法.
现在我已经为这种方法做过研究,人们把它比作Java方法.run()- 参见Interface Runnable.
经过长时间的努力思考,我无法想到为什么你会打电话$obj(); 而不是$obj->function();
即使您在一个对象数组上进行迭代,您仍然可以知道要运行的主函数名称.
那么__invoke魔术方法的另一个例子是'因为你可以,并不意味着你应该'在PHP中使用快捷方式,或者是否有这种情况实际上是正确的做法?
我有一个抽象的父类Mongo_Document(来自mongodb-php-odm)和一个继承的类Model_ActionPlan. Mongo_Document具有与Mongo_Document类内部数组交互的magic __isset和__get方法.
我试图使用以下代码(从方法内部的代码片段Model_ActionPlan):
if (isset($this->status))
{
if (($this->status === "closed") AND ($this->close_type != "failure"))
{
return;
}
}
Run Code Online (Sandbox Code Playgroud)
(注意,close_type如果是,则保证设置status == 'closed'.)
该isset调用返回true,然后继续执行下一条语句.在那里,我收到以下错误:
Undefined property: Model_ActionPlan::$status
Run Code Online (Sandbox Code Playgroud)
但是,如果我替换$this->status为parent::__get('status'),则此代码按预期工作.请注意,在程序的其他任何地方,我都可以使用:
$ap = new Model_ActionPlan($plan_id);
echo $ap->status;
// Prints 'closed' (or 'active') as expected
Run Code Online (Sandbox Code Playgroud)
只有在这里,在课堂内部,这不起作用.
我环顾四周,似乎无法找到任何说明在子类中无法调用魔法的方法.我可以使用该parent::__get调用,但我认为这可能是错误的方法.有谁知道是否有正确/更好的方法来做到这一点?
更新了#1 2012-12-16: 父类的完整代码在Github上.
更新了#2 2012-12-18:
对于询问设置在何处或是否设置正确的人,答案是,由于调用parent::__get('status') 确实有效,问题显然不是变量没有设置.它__get()是从一个名为的私有instace变量中获取数据的 …
考虑以下令人厌恶的类:
class MapInt:
__call__ = int
def __sub__(self, other):
return map(self, other)
__add__ = map
Run Code Online (Sandbox Code Playgroud)
然后可以map(int, lst)通过调用MapInt() - lst,即
assert list(MapInt() - ['1','2','3'])) == [1,2,3] # passes
Run Code Online (Sandbox Code Playgroud)
然而,加法就不那么合作了:
assert list(MapInt() + ['1','2','3'])) == [1,2,3] # TypeError: map() must have at least two arguments.
Run Code Online (Sandbox Code Playgroud)
这个奇怪的现象可以通过直接调用magic方法来解决:
assert list(MapInt.__add__(MapInt(), ['1','2','3'])) == [1,2,3] # passes
assert list(MapInt().__add__(MapInt(), ['1','2','3'])) == [1,2,3] # passes
Run Code Online (Sandbox Code Playgroud)
所以我的问题是,什么给出了?直接赋值__add__似乎“丢弃”了self参数,但是调用方法本身或以标准方式定义它效果很好。
为什么可以这样初始化Dictionary<T1,T2>:
var dict = new Dictionary<string,int>() {
{ "key1", 1 },
{ "key2", 2 }
};
Run Code Online (Sandbox Code Playgroud)
...但是不要以KeyValuePair<T1,T2>完全相同的方式初始化一组对象:
var kvps = new KeyValuePair<string,int>[] {
{ "key1", 1 },
{ "key2", 2 }
};
// compiler error: "Array initializers can only be used in a variable
// or field initializer. Try using a new expression instead."
Run Code Online (Sandbox Code Playgroud)
我意识到我可以通过new KeyValuePair<string,int>() { "key1", 1 }为每个项目编写等来使第二个例子工作.但我想知道是否可以使用第一个示例中可能的相同类型的简洁语法.
如果不可能,那么是什么让Dictionary类型如此特别?
注释(在PHPDoc中)通过实现的函数的正确方法是什么__callStatic?更重要的是:有没有办法让NetBeans 和 PHPStorm理解这些是静态方法?
如果你想要更大的图片,这就是我对这个问题的看法.
问题:在我目前的项目中,我们有很多类应该是单例(DB代理等).不用说,我们至少有几百require_once并$foo = new FooProxy();线.
解决方案:我创建了一个Loader类来解决这个问题,使用__callStatic魔术方法,所以我们可以说$foo = Loader::FooProxy();.它非常适合我们的目的,但是:
问题:这种方式在团队中使用的IDE中显然没有类型提示.
解决方案:每个模块定义一个子类Loader,添加仅路由到的方法__callStatic.
问题:为了自动完成而添加实际解释的代码是不可接受的(这可以争论,但让我们暂时接受它).
解决方案:我们不添加任何实际方法,只需在PHPDoc中声明方法如下:
<?php
/**
* @method FooProxy FooProxy()
*/
class BarLoader extends Loader {}
?>
Run Code Online (Sandbox Code Playgroud)
问题:FooProxy不是静态方法.以下所有内容都不会使其成为静态:
<?php
/**
* @static
* @method FooProxy FooProxy()
*/
///////////////
/**
* @static @method A A()
* @method static A A()
* @method A …Run Code Online (Sandbox Code Playgroud) 我知道神奇的IPython %paste命令,如果你有有效的代码插入,这是非常有用的.现在我不想插入代码,我只想将复制缓冲区中的一些字符串存储为变量.有没有更简单的方法,除了将字符串复制到一些单独的文本编辑器并首先修改它?
像这样的东西会很好,但它们都不起作用:
strvar = %paste
strvar = """%paste"""
Run Code Online (Sandbox Code Playgroud)
PS字符串很长,包含特殊的字符等.所以简单的ctrl-c只会创建垃圾和错误消息.
在PHP文件说,下面讲__call()魔术方法:
在对象上下文中调用不可访问的方法时会触发__call().
在__call()调用实际方法之前,即使方法存在,我是否可以调用?或者,是否有其他钩子我可以实现或提供此功能的另一种方式?
如果它很重要,这是为了static function(我实际上更愿意使用__callStatic).
我想使用这些运算符的魔术方法进行bool二进制运算.例如,我可以得到a < b作为getattr(a, '__lt__')(b)或a == b作为getattr(a, '__eq__')(b).
我能得到a in b并且a is b以这样的方式?
我有一个自定义类,
class A:
def __init__(self, a, b):
self.a = a
self.b = b
Run Code Online (Sandbox Code Playgroud)
该类不可迭代或可索引或类似的东西.如果可能的话,我想保持这种方式.有可能像以下工作一样吗?
>>> x = A(1, 2)
>>> min(x)
1
>>> max(x)
2
Run Code Online (Sandbox Code Playgroud)
让我想到这一点的是,min并max在文档中列为"通用序列操作" .由于range被同一个文档认为是序列类型,我认为必须有某种可能的优化range,也许我可以利用它.
也许有一种我不知道的神奇方法可以实现这一点吗?
为什么下面的代码会出错?
class Foo:
def __new__(cls, *args, **kwargs):
print("Creating Instance")
instance = super(Foo, cls).__new__(cls,*args, **kwargs)
return instance
def __init__(self, a, b):
self.a = a
self.b = b
z= Foo(2,3)
Run Code Online (Sandbox Code Playgroud)
它给出了以下错误
TypeError: object.__new__() takes exactly one argument (the type to instantiate)
Run Code Online (Sandbox Code Playgroud) magic-methods ×10
python ×5
php ×4
python-3.x ×2
assign ×1
c# ×1
class ×1
copy-paste ×1
getattr ×1
inheritance ×1
ipython ×1
mongodb-php ×1
oop ×1
phpdoc ×1
syntax ×1