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'sconstructor
already.__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
})
Side note: I was able to remove the main constraint (not being able to access child props in parent magic methods) from the implementation by instantiating objects using
Reflect.construct(target, args, receiver)
instead ofnew target(...args)
.