locutus
Version:
Locutus other languages' standard libraries to JavaScript for fun and educational purposes
59 lines (58 loc) • 2.28 kB
JavaScript
import { resolvePhpCallable } from "../_helpers/_callbackResolver.js";
import { getPhpGlobalEntry, getPhpObjectEntry } from "../_helpers/_phpRuntimeState.js";
import { isObjectLike, isPhpCallable, } from "../_helpers/_phpTypes.js";
export function call_user_func_array(cb, parameters) {
// discuss at: https://locutus.io/php/call_user_func_array/
// original by: Thiago Mata (https://thiagomata.blog.com)
// revised by: Jon Hohle
// improved by: Brett Zamir (https://brett-zamir.me)
// improved by: Diplom@t (https://difane.com/)
// improved by: Brett Zamir (https://brett-zamir.me)
// note 1: Callback resolution intentionally avoids eval/new Function for security.
// example 1: call_user_func_array('isNaN', ['a'])
// returns 1: true
// example 2: call_user_func_array('isNaN', [1])
// returns 2: false
let func;
let scope = null;
try {
const resolved = resolvePhpCallable(cb, { invalidMessage: 'invalid' });
func = resolved.fn;
scope = resolved.scope;
}
catch {
// Fall back to legacy-compatible callback resolution paths below.
}
if (!func && typeof cb === 'string') {
const globalCandidate = getPhpGlobalEntry(cb);
if (isPhpCallable(globalCandidate)) {
func = globalCandidate;
}
}
else if (!func && Array.isArray(cb)) {
if (typeof cb[0] === 'string') {
const globalScope = getPhpGlobalEntry(cb[0]);
if (isObjectLike(globalScope) || typeof globalScope === 'function') {
const method = getPhpObjectEntry(globalScope, String(cb[1]));
if (isPhpCallable(method)) {
func = method;
}
scope = globalScope;
}
}
else if (isObjectLike(cb[0]) || typeof cb[0] === 'function') {
const method = getPhpObjectEntry(cb[0], String(cb[1]));
if (isPhpCallable(method)) {
func = method;
}
scope = cb[0];
}
}
else if (!func && isPhpCallable(cb)) {
func = cb;
}
if (!func) {
throw new Error(String(cb) + ' is not a valid function');
}
return func.apply(scope, parameters);
}