JavaScript call_user_func
Call a user function which is the first parameter
1 2 3 4 56 7 8 9 1011 12 13 14 1516 17 18 19 2021 22 23 24 2526 27 28 | function call_user_func (cb) { // Call a user function which is the first parameter // // version: 1008.1718 // discuss at: http://phpjs.org/functions/call_user_func // + original by: Brett Zamir (http://brett-zamir.me) // + improved by: Diplom@t (http://difane.com/) // + improved by: Brett Zamir (http://brett-zamir.me) // * example 1: call_user_func('isNaN', 'a'); // * returns 1: true var func; if (typeof cb === 'string') { func = (typeof this[cb] === 'function') ? this[cb] : func = (new Function(null, 'return ' + cb))(); } else if (cb instanceof Array) { func = ( typeof cb[0] == 'string' ) ? eval(cb[0]+"['"+cb[1]+"']") : func = cb[0][cb[1]]; } else if (typeof cb === 'function') { func = cb; } if (typeof func != 'function') { throw new Error(func + ' is not a valid function'); } var parameters = Array.prototype.slice.call(arguments, 1); return (typeof cb[0] === 'string') ? func.apply(eval(cb[0]), parameters) : ( typeof cb[0] !== 'object' ) ? func.apply(null, parameters) : func.apply(cb[0], parameters); } |
Examples
Running
1 | call_user_func('isNaN', 'a'); |
Should return
1 | true |
Dependencies
No dependencies, you can use this function standalone.
Open syntax issues
php.js uses JsLint to help us keep our code consistent and prevent some common bugs.
Eventually we want all code to pass or at least take into consideration most fixes suggested by JsLint, following this JsLint configuration we’ve decided on.
Authors
Thanks to the following developers, you get to have call_user_func goodness in JavaScript.
I don't know about the errors with Rhino, but maybe that is due to going through window properties?
I concur with your steps of waiting to build a module, and might suggest also waiting for all arguments to be implemented (unless impossible) for any completed functions.
Is it ok for me to move interface_exists() and get_declared_interfaces() (and to add class_implements()) to not porting? JavaScript has no built-in interfaces, so we could not implement these without adding our own language constructs to JavaScript.
@ Brett Zamir: They keep giving me
[CODE="Javascript"]
Exception in thread "Thread-0" org.mozilla.javascript.EcmaError: TypeError: Cannot read property "prototype" from undefined
[/CODE]
..errors, even when I check for prototype first. Rhino issue maybe.
Concidering the functions that are in unported/notporting, etc. That has never been a scientific process. It was the result of a sleepless night of crawling php.net. It has never been more than a rough guideline and has always been open to suggestions.
Bringing me to SPL. I think that may be taking it to another level. That can be a good or a bad thing, but I think for now we should focus on the normal functions & the site of the project. But that's my humble opinion, I'm open to ideas.
btw I think we should move deprecated functions to _notporting, so that's what I did for now.
As far as the Mozilla thing goes. I have actually never made an extension or anything but Yeah it would be cool if we're included at some point. I don't know if they're interested or anything, but no harm in asking, right?
I do think we should further professionalize PHP.JS before taking such steps though.
In my eyes mainly meaning:
- bugfixing
- porting more _unported
- making everything associative-aware
- move out the development process to phpjs.org
- deciding on a good 'default' package that doesn't contain any controversial functions
Sorry, also realized the new one I just submitted now for get_class_vars() should have variable names changed to reflect the behavior of this function:
[CODE="Javascript"]
function get_class_vars (name) {
var constructor, retArr={};
if (typeof name === 'function') {
constructor = name;
}
else if (typeof name === 'string') {
constructor = window[name];
}
for (var prop in constructor) {
if (typeof constructor[prop] !== 'function' && prop !== 'prototype') {
retArr[prop] = constructor[prop];
}
}
// Comment out this block to behave as "class" is usually defined in JavaScript convention
for (var prop in constructor.prototype) {
if (typeof constructor.prototype[prop] !== 'function') {
retArr[prop] = constructor.prototype[prop];
}
}
return retArr;
}[/CODE]
Sorry, just realized that get_class_method() returns an associative array. Here it is again, along with get_class_vars() and get_object_vars():
[CODE="Javascript"]
function Myclass () {this.privMethod = function(){}}
Myclass.classMethod = function () {}
Myclass.prototype.myfunc1 = function () {
return(true);
};
Myclass.prototype.myfunc2 = function () {
return(true);
}
whatIs(get_class_methods('Myclass'));
var myClassObj = new Myclass();
whatIs(get_class_methods(myClassObj));
function get_class_methods (name) {
var constructor, retArr={};
if (typeof name === 'function') {
constructor = name;
}
else if (typeof name === 'string') {
constructor = window[name];
}
else if (typeof name === 'object') {
constructor = name;
for (var method in constructor.constructor) { // Get class methods of object's constructor
if (typeof constructor.constructor[method] === 'function') {
retArr[method] = constructor.constructor[method];
}
}
// return retArr; // Uncomment to behave as "class" is usually defined in JavaScript convention (and see comment below)
}
for (var method in constructor) {
if (typeof constructor[method] === 'function') {
retArr[method] = constructor[method];
}
}
// Comment out this block to behave as "class" is usually defined in JavaScript convention (and see comment above)
for (var method in constructor.prototype) {
if (typeof constructor.prototype[method] === 'function') {
retArr[method] = constructor.prototype[method];
}
}
return retArr;
}[/CODE]
and:
[CODE="Javascript"]
function Myclass () {this.liveProp = 'prop';}
Myclass.classProp = 'classPropVal';
Myclass.prototype.myprop1 = 1;
Myclass.prototype.myprop2 = 2;
whatIs(get_class_vars('Myclass'));
var myClassObj = new Myclass();
myClassObj.prototype = {a:'b'};
function get_class_vars (name) {
var constructor, retArr={};
if (typeof name === 'function') {
constructor = name;
}
else if (typeof name === 'string') {
constructor = window[name];
}
for (var method in constructor) {
if (typeof constructor[method] !== 'function' && method !== 'prototype') {
retArr[method] = constructor[method];
}
}
// Comment out this block to behave as "class" is usually defined in JavaScript convention
for (var method in constructor.prototype) {
if (typeof constructor.prototype[method] !== 'function') {
retArr[method] = constructor.prototype[method];
}
}
return retArr;
}
function get_object_vars (obj) {
var retArr={};
for (var prop in obj) {
if (typeof obj[prop] !== 'function' && prop !== 'prototype') {
retArr[prop] = obj[prop];
}
}
for (var prop in obj.prototype) {
if (typeof obj.prototype[prop] !== 'function') {
retArr[prop] = obj.prototype[prop];
}
}
return retArr;
}[/CODE]
Here's another.... get_class_method(). I've left comments on how to get only the "class methods" as typically used in JavaScript (as opposed to PHP) terminology (i.e., not privileged or prototype methods, but those in the class "namespace").
[CODE="Javascript"]function Myclass () {this.privMethod = function(){}}
Myclass.classMethod = function () {}
Myclass.prototype.myfunc1 = function () {
return(true);
};
Myclass.prototype.myfunc2 = function () {
return(true);
}
alert(get_class_methods('Myclass')); // classMethod,myfunc1,myfunc2
var myClassObj = new Myclass();
alert(get_class_methods(myClassObj));
function get_class_methods (name) {
var constructor, retArr=[];
if (typeof name === 'function') {
constructor = name;
}
else if (typeof name === 'string') {
constructor = window[name];
}
else if (typeof name === 'object') {
constructor = name;
for (var method in constructor.constructor) { // Get class methods of object's constructor
if (typeof constructor.constructor[method] === 'function') {
retArr.push(method);
}
}
// return retArr; // Uncomment to behave as "class" is usually defined in JavaScript convention (and see comment below)
}
for (var method in constructor) {
if (typeof constructor[method] === 'function') {
retArr.push(method);
}
}
// Comment out this block to behave as "class" is usually defined in JavaScript convention (and see comment above)
for (var method in constructor.prototype) {
if (typeof constructor.prototype[method] === 'function') {
retArr.push(method);
}
}
return retArr;
}[/CODE]
Also, for get_declared_interfaces() and interface_exists() (and class_implements() but you don't seem to have these in your imported list: http://cn.php.net/manual/en/ref.spl.php -- btw, is it easy to say which modules you included/excluded?), since JavaScript offers no formal way to implement interfaces, do you want to move these to not porting? We could implement our own interface system (which even checked the number of arguments, etc.) and which worked with these PHP-named functions, but I presume that is beyond your intended scope here (though it would be pretty cool to pseudo-standardize on an interface system for JavaScript, at least until JS 2.0).
Off the topic, as far as the php_js global, in the namespaced version of PHP.JS, you could put that at the top of the (function())() closure namespacing, so it wasn't actually global.
And another off-the-topic, https://wiki.mozilla.org/Labs/JS_Modules , they state there "If you would like to contribute a new module, get in touch with us at #labs!", so at whatever point you think we have something, we can submit a PHP-JS module for Mozilla so a bunch of extensions (and the same extension) could be able to reuse the module without any additional loading cost!
Hi Kevin,
call_user_method() and call_user_method_array() are now deprecated in PHP in favor of call_user_function (with the array argument). Do you want to move to not porting, or use the following?
[CODE="Javascript"]function call_user_method(method, obj) {
// http://kevin.vanzonneveld.net
// + original by: Brett Zamir
var func = eval(obj+"['"+method+"']");
if (typeof func != 'function') {
throw new Exception(func + ' is not a valid method');
}
return func.apply(null, Array.prototype.slice.call(arguments, 2));
}
function call_user_method_array(method, obj, params) {
// http://kevin.vanzonneveld.net
// + original by: Brett Zamir
var func = eval(obj+"['"+method+"']");
if (typeof func != 'function') {
throw new Exception(func + ' is not a valid method');
}
return func.apply(null, params);
}[/CODE]


Kevin van Zonneveld
11 Feb '09