Skip to content

Instantly share code, notes, and snippets.

@adinan-cenci
Last active July 7, 2023 06:10
Show Gist options
  • Save adinan-cenci/ed4f23eb719e4c2820aedc5feb91032b to your computer and use it in GitHub Desktop.
Save adinan-cenci/ed4f23eb719e4c2820aedc5feb91032b to your computer and use it in GitHub Desktop.
How to emulate the php __call method in JavaScript
/**
* PHP's __call magic method is pretty useful. Unfortunately
* there is no equivalent in JavaScript, but it can be
* emulated with Proxy:
*/
magicMethodsProxy =
{
get: function(target, prop, receiver)
{
// Does prop exists? Is it a method?
if (target[prop] != undefined && typeof target[prop] == 'function') {
// Wrap it around a function and return it
return function(...args)
{
// in order to preserve the default arguments the method may have, we pass undefined
// instead of an empty arguments object
var value = target[prop].apply(target, (args.length ? args : undefined) );
// it is important to return the proxy instead of the target in order to make
// future calls to this method
return value == target ? this : value;
}
}
// Does prop exists?
if (target[prop] != undefined) {
return target[prop];
}
// Falls to __call
return function(...args)
{
return target.__call(prop, args, this);
};
}
}
/*---------------------------*/
class Music
{
constructor(file)
{
this.file = file;
this.currentTime = 0;
this.metadata =
{
title : '',
artist: '',
lyrics: ''
};
// return the proxy
return new Proxy(this, magicMethodsProxy);
}
__call(method, args, proxy)
{
if (this.metadata[method] == undefined) {
throw 'Method "'+method+'" is undefined';
}
this.metadata[method] = args[0];
// again, it is important to return the proxy
// instead of the target
return proxy;
}
play(seconds = 0)
{
this.seconds = seconds;
return this;
}
}
/*---------------------------*/
var music = new Music('the-bards-song-the-hobbit.mp3');
music.play(50) // an actual method
.title("The Bard's song: The Hobbit") // not a method
.artist("Blind Guardian")
.lyrics(`Out in the distance
There's so much gold
The treasure that I've found
Is more than enough
Far to the hill we've to go
Over the moutains and ...`);
console.log(music.seconds); // 50
console.log(music.metadata.title); // The Bard's song: The Hobbit
music.blindGuardianSux('just kiding, it is awesome.'); // throw exception
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment