PHP等效的PHP __call

时间:2012-04-19 10:20:43

标签: javascript

在PHP中,您可以检测方法何时被调用,即使它没有使用" magic" __call功能。

public function __call($methodName, $args)
{
    // do something
}

您可以调用任何方法,并将名称和参数传递给此魔法全部。

JavaScript中是否有类似的技术允许调用任何方法,即使它实际上并不存在于对象上?

var foo = (function () {
    return {
         __call: function (name, args) { // NOT REAL CODE
             alert(name); // "nonExistent"
         }
    }
}());

foo.nonExistent();

5 个答案:

答案 0 :(得分:20)

使用ES6 Proxy API

可以
var myObj = {};
var myProxy = new Proxy(myObj, {
  get: function get(target, name) {
    return function wrapper() {
      var args = Array.prototype.slice.call(arguments);
      console.log(args[0]);
    }
  }
});
console.log(myProxy.foo('bar'));  // prints 'bar'

MDN上提供了浏览器兼容性。截至2017年8月,除Internet Explorer之外的所有浏览器(包括Microsoft Edge)都支持它。

有关代理的详细信息,请参阅this answer

答案 1 :(得分:9)

您可以在Firefox中使用__noSuchMethod__。不幸的是,这是非标准的...

相关问题:Is there an equivalent of the __noSuchMethod__ feature for properties, or a way to implement it in JS?

答案 2 :(得分:3)

没有。由于JavaScript的工作方式,等价物就像Python的__getattr__ / __getitem__,而不是PHP的__call,因为在检索属性时需要处理它,而不是在调用时它

然后,您可以查看像Python's __getattr__ in Javascript这样以这种方式回答问题的问题。

另见以下问题:

答案 3 :(得分:2)

建立@ amirnissim的回答。

正如我们大多数人可能已经意识到的那样,ES6 introduces the Proxy API允许我们创建一个对象(Proxy对象)来捕获对该对象的调用,从而为我们提供了一个" route&#的机会。 34;用户在对象上调用的属性,无论我们想要什么。

模仿PHP的魔术方法

很遗憾没有办法使用Proxy对象扩展类,但我们可以做的是设置一个中间步骤将对象转换为代理,并将任何传入的方法调用路由到对象本身可用的方法:

class MyProxy
{
    constructor ()
    {
        return this.asProxy()
    }

    /**
     * Return as a proxy with this object as its target.
     */
    asProxy ()
    {
        let handler = {
            /**
             * This function is called whenever any property on the Proxy 
             * is called.
             * 
             * @param target the "parent" object; the object the proxy 
             *        virtualizes
             * @param prop the property called on the Proxy
             */
            get: function (target, prop)
            {
                /* This will return the property on the "parent" object
                 */
                if (typeof target[prop] !== 'undefined')
                    return target[prop]

                // TODO: implement custom logic
            }
        }

        return new Proxy(this, handler)
    }
}

这实质上为您提供了与PHP的魔术__get方法和__call方法相同的功能。至于__call版本,我们只是返回一个函数供用户输入参数。

展示以上

为了使用它,我们首先在TODO: implement custom logic所在的地方添加一些自定义逻辑:

if (prop === 'helloWorld')
    return function () { console.log("Hello, world!") }
else
    return function () { console.log("Where art thou, hello world?") }

如果我们继续创建MyProxy类的新实例,我们可以触发我们实现的自定义逻辑:

let myProxy = new MyProxy()

myProxy.test()
myProxy.hello()
myProxy.helloWorld()

以上示例输出:

  

Where art thou, hello world?
  Where art thou, hello world?
  Hello, world!

当然,也可以从get函数返回任何其他类型的值,我们也可以返回一个字符串或整数。

易于使用;通过继承使用

为了使这更容易使用,我可以建议将asProxy方法包装到另一个类中,然后简单地扩展任何需要"魔术方法的类#34;包含asProxy方法的类的功能?只需从构造函数中返回asProxy方法,基本上就可以获得与PHP中相同的功能。

当然,还需要get method稍微可编辑,以便仍然可以从子类处理自定义逻辑。也许通过向return this.asProxy(() => {})发送一个闭包,然后从get函数本身调用?或者甚至可能将get函数路由到get对象上的target方法?

但请记住,这只适用于ES6。 Transpilers such as Babel不能,and I quote

  

由于ES5的限制,代理无法进行转换或填充。

只要符合这一条件,上述解决方案确实可以很好地工作。例如,它是Node.js中完全可行的选项。

答案 4 :(得分:0)

虽然这不是一种优雅的方式,因为我们已经推断出JavaScript没有__callmethod_missing__getattr__,因此可以创建属性组合来创建具体功能转发到单个方法,传递用于创建它的属性。

一个例子是Myriad.js