This script implements some of PHP's magic methods for JavaScript classes, using a Proxy.
You can use it like this:
const Foo = magicMethods(class Foo {
constructor () {
this.bar = 'Bar'
}
__get (name) {
return `[[${name}]]`
}
})
const foo = new Foo
foo.bar // "Bar"
foo.baz // "[[baz]]"If you're using a JavaScript transpiler like Babel or TypeScript with decorators enabled, you can also use the magicMethods function as a decorator:
@magicMethods
class Foo {
// ...
}Given a class Class and an instance of it, the following are the magic methods supported by this script:
Called when trying to access instance[name] where name is not an existing property of instance.
Attention: As in PHP, the check if name exists in instance does not use any custom __isset() methods.
Called when trying to do instance[name] = ... where name is neither set as a property of instance.
Called when trying to check existance of name by calling name in instance.
Called when trying to unset property name by calling delete instance[name].
The following magic methods are made available by this script, but are not supported in PHP:
Like __get(), but in the Class instead of the instance.
Like __set(), but in the Class instead of the instance.
They are either not necessary or not practical:
__construct()is not needed, there's JavaScript'sconstructoralready.__destruct(): There is no mechanism in JavaScript to hook into object destruction.__call(): Functions are first-class objects in JavaScript. That means that (as opposed to PHP) an object's methods are just regular properties in JavaScript and must first be obtained via__get()to be invoked subsequently. So to implement__call()in JavaScript, you'd simply have to implement__get()and return a function from there.__callStatic(): As in__call(), but with__getStatic().__sleep(),__wakeup(): There's no builtin serialization/unserialization in JavaScript. You could useJSON.stringify()/JSON.parse(), but there's no mechanism to automatically trigger any methods with that.__toString()is already present in JavaScript'stoString()__invoke(): JavaScript will throw an error if you'll try to invoke a non-function object, no way to avoid that.__set_state(): There's nothing likevar_export()in JavaScript.__clone(): There's no builtin cloning functionality in JavaScript that can be hooked into.__debugInfo(): There's no way to hook intoconsole.log()output.
Yes:
// `Bar` inherits magic methods from `Foo`
class Bar extends Foo {}Or, if class Bar contains magic methods itself:
const Bar = magicMethods(class Bar extends Foo {
// You may define `Bar`'s magic methods here
})
You cannot directly use
__getlike__call, but you can work around it.In PHP, calling a method
$foo->bar()is different from accessing a property$foo->bar, which is why__getand__callcan be distinguished.In JavaScript however, calling a method
foo.bar()actually just fetches thebarproperty, assumes that it's a function and calls it. In PHP terms, a method call in JavaScript is a__get, followed by an__invokeon its return value. The PHP equivalent would be this:So in JavaScript, you don't actually acces the arguments in the
__getmethod itself, but from the__getmethod you return a function which receives arguments.This means to access the arguments when calling
foo.bar(1, 2, 3), you would do this:By the way: Since calling a method in JavaScript just means plucking the method property from the object and then invoking it, you actually cannot overload the same name as a property access and a method call (which works in PHP).