'How I can simulate the __callStatic property of PHP in Node.js using Proxy?
I'm trying to create the same behavior of PHP __callStatic
magic method in Node.js.
I'm trying to use Proxy
to do that, but I don't really know if it's the best option.
class Test {
constructor() {
this.num = 0
}
set(num) {
this.num = this.num + num
return this
}
get() {
return this.num
}
}
const TestFacade = new Proxy({}, {
get: (_, key) => {
const test = new Test()
return test[key]
}
})
// Execution method chain ends in get
console.log(TestFacade.set(10).set(20).get())
// expected: 30
// returns: 0
// Start a new execution method chain and should instantiate Test class again in the first set
console.log(TestFacade.set(20).set(20).get())
// expected: 40
// returns: 0
The problem is that the get
trap is fired every time that I try to access a property of TestFacade
. The behavior that I need is that when the set
method is called it will return this
of Test
class and I can even save the instance for latter usage!
const testInstance = TestFacade.set(10) // set method return this of `Test` not the Proxy
If something isn't clear, please let me know.
Solution 1:[1]
I don't know if it's the best option. But I solved it, returning a new Proxy inside get
trap that uses the apply
trap to bind the test
class instance into the method:
class Facade {
static #facadeAccessor
static createFacadeFor(provider) {
this.#facadeAccessor = provider
return new Proxy(this, { get: this.__callStatic.bind(this) })
}
static __callStatic(facade, key) {
/**
* Access methods from the Facade class instead of
* the provider.
*/
if (facade[key]) {
return facade[key]
}
const provider = new this.#facadeAccessor()
const apply = (method, _this, args) => method.bind(provider)(...args)
if (provider[key] === undefined) {
return undefined
}
/**
* Access the properties of the class.
*/
if (typeof provider[key] !== 'function') {
return provider[key]
}
return new Proxy(provider[key], { apply })
}
}
class Test {
num = 0
set(num) {
this.num = this.num + num
return this
}
get() {
return this.num
}
}
const TestFacade = Facade.createFacadeFor(Test)
console.log(TestFacade.set(10).set(20).get()) // 30
console.log(TestFacade.set(5).set(5).get()) // 10
const testInstance = TestFacade.set(10)
console.log(testInstance.num) // 10
console.log(testInstance.get()) // 10
console.log(testInstance.set(10).get()) // 20
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | João Lenon |