This document provides operational context, architecture directives, and guidance for AI agents working on the @nexustools/php codebase.
-
Synchronous PHP / Asynchronous JS: PHP code semantics appear synchronous to the PHP script, but transpiled JavaScript code MUST run asynchronously using
async/awaitso Node.js can handle concurrent execution without blocking the event loop. -
PHPReference&PHPLiteralSystem:-
PHPReferenceInterface: Standardized interface for all variables, references, and literal values in the runtime (get(),set(val),bindRef(target),unbindRef(),isReference(),call(ctx, method, args)). -
PHPVariableClass: ImplementsPHPReferencefor mutable state, global variable bindings, reference aliasing (bindRef), and direct method invocation (call). -
PHPLiteralClass: ImplementsPHPReferencefor immutable literal values (strings, numbers, booleans, arrays, null). Invokingset()on aPHPLiteralthrows aPHPFatalError("Literals cannot be changed"), and invokingcall()on non-objects throwsPHPFatalError("Call to a member function ... on a non-object"). -
Engine Constants:
PHPEngineexposes static cached literal instances (PHPEngine.TRUE,PHPEngine.FALSE,PHPEngine.NULL) to reduce object allocations. -
Function Signatures: All exposed PHP runtime functions and extension functions accept
PHPReferencearguments (...args: PHPReference[]).- PHP Class Layout in JS:
- Classes exposed to PHP from JavaScript MUST follow a specific parameter layout for methods and constructors.
- Method Signatures: All exposed PHP class methods MUST conform to the signature
(ctx: PHPContext, ...args: PHPReference[]) => any;. - Constructors: Instead of using the native JavaScript
constructor, exposed classes MUST use apublic async __construct(ctx: PHPContext, ...args: PHPReference[])instance method. - Properties: Static and instance properties MUST be initialized as
PHPVariableinstances so they can be passed by reference. (e.g.public $myProp: PHPReference = new PHPVariable("default");). Access them via.get()and.set()within JavaScript. - Instantiation Factory: To proxy object instantiation and properly set up the object without invoking native
constructor, you MUST provide apublic static async __$$__new(ctx: PHPContext, ...args: PHPReference[]): Promise<YourClass>factory method. This method should create the object viaObject.create(this.prototype)and call its__constructmethod. - Example:
export class MyClass { public static [SYMBOL_PHP_NAME] = "MyClass"; public $myProp!: PHPReference; public static async __$$__new(ctx: PHPContext, propArg?: PHPReference): Promise<MyClass> { const obj = Object.create(this.prototype); obj.$myProp = new PHPVariable(); await obj.__construct(ctx, propArg); return obj; } public async __construct(ctx: PHPContext, propArg?: PHPReference): Promise<void> { this.$myProp.set(propArg ? String(propArg.get() ?? "") : "default"); } public async myMethod(ctx: PHPContext, arg1?: PHPReference): Promise<any> { /* ... */ } }
- PHP Class Layout in JS:
-
-
Raw Metal Execution Directives:
- All class names, function names, and constant names should be transpiled to lowercase for case-insensitivity.
- Classes & Instantiation:
- Class resolution in transpiled JS uses
ctx.classes[classname] ?? (await ctx.resolveMissingClass(classname, originalClassName)). - Instantiating a PHP class MUST be transpiled to calling the static
__$$__newfactory method (await ClassName.__$$__new(ctx, ...args)orawait (ctx.classes[classname] ?? await ctx.resolveMissingClass(classname)).__$$__new(ctx, ...args)), and MUST NEVER be transpiled tonew ClassName(...).
- Class resolution in transpiled JS uses
- Constants: Global constant lookups in transpiled JS use
ctx.constants[constantname] ?? originalconstantname. - Functions: Function calls are resolved directly from
ctx.functionsin the transpiled JS. E.g.,(ctx.functions["foo"] ?? ctx.functionMissing("foo"))(ctx, ...args). - Properties & Methods:
- Properties in transpiled JS are accessed with a
$prefix (e.g.$obj.$propName), while method calls do not use a$prefix (e.g.$obj.methodName(ctx, ...args)). - Magic Methods Proxy: When a class defines magic methods (
__get,__set,__call), its__$$__newmethod wraps the instance in a JSProxy:- Property accesses (keys starting with
$) checkprop in targetor calltarget.__get(ctx, prop.slice(1)). - Method accesses (keys not starting with
$) checktypeof target[prop] === "function"or return a wrapper callingtarget.__call(ctx, prop, args). - Property assignments starting with
$set the target property or calltarget.__set(ctx, prop.slice(1), val).
- Property accesses (keys starting with
- Non-magic classes return raw instance objects without Proxy overhead.
- Properties in transpiled JS are accessed with a
- Error Handling & JS Error Wrapping:
- Native JavaScript errors thrown during execution (like
TypeErrororReferenceError) are caught by PHPtry/catchblocks and converted into PHPErrorinstances viaPHPError.wrapJSError(err). - Stack traces are standardized in
PHPErrorto reflect PHP source line numbers or the original JavaScript/TypeScript source line numbers.
- Native JavaScript errors thrown during execution (like
-
AST Optimization & Cache Revision:
ASTOptimizeroptimizesextension_loaded(...),defined(...),constant(...), constant references (name/constref), and boolean expressions at compile time.PHPEngine.REVISION(integer) andPHPEngine.VERSION("8.5.0") are included inPHPEngine.getConfigurationSHA1()to automatically invalidate stale disk cache files (os.tmpdir()/jsphp_cache) whenever the transpiler or runtime revision changes.
-
CLI & Server Binaries:
php(bin/php.js): Command-line interface powered bycommandersupporting standard PHP CLI flags (-v,-a,-r,-l,-m,-i,-f,-c,-n,-d,--ini,--rf,--rc,--re,--ri,-B,-R,-F,-E).php-fpm(bin/php-fpm.js): FastCGI (FCGI 1.0) binary socket server for Nginx/Apache proxying.php-http-server(bin/php-http-server.js): HTTP web server supporting static file serving and smart URL resolution (/->index.php/index.html,/test->test.php/test.html/test/index.php).
-
Output Buffering & Flush Lifecycle:
- Output buffering (
OutputBufferStack) handles nestedob_start(),ob_get_clean(),ob_flush(),ob_end_flush()buffers cleanly. - Unbuffered
echoat buffer level 0 immediately outputs toctx.writeStdout. - Top-level
requireandevalexecute shutdown functions (runShutdownFunctions()) and flush remaining output buffers (outputBuffer.flushAll(this)) infinallyblocks upon completion.
- Output buffering (
-
Internal Variables (
internalVars):PHPEngineandPHPContextmaintaininternalVars(Map<string, any>) that are invisible to PHP userland ($GLOBALS,get_defined_vars(), Reflection), but accessible to internal engine methods, AST optimization, and server handlers. -
Header & Response Lifecycle: HTTP response functions (
header,setcookie,setrawcookie,header_remove,headers_list,headers_sent,http_response_code) operate onPHPResponseattached toPHPContext. Calling header functions in CLI mode without a registered server response handler throws aPHPWarning/PHPError. -
Error Handling &
set_error_handler: Supportsset_error_handler,restore_error_handler,trigger_error,error_reporting, andErrorException. Errors thrown within PHP methods use subclasses ofPHPError(PHPFatalError,PHPWarning,PHPNotice,PHPTypeError, etc.). -
Reflection Metadata & JS Source Fallback: Function/method metadata is tracked via
.phpMetaattached bydefineFunction. If.phpMetais absent,ReflectionFunctionandReflectionMethodfall back to parsing the function's JavaScript.toString()source declaration. -
Optional Node.js Interop (
nodejsextension): Provides Node.js module loading (njs_import/nodejs_require), global variable access (njs_global/nodejs_global), eval (njs_eval/nodejs_eval), and instantiation (njs_new/nodejs_new). JavaScript objects are wrapped via a Proxy usingSYMBOL_PHP_NODEJS_PROXYandSYMBOL_PHP_NODEJS_VALUEsymbols (declared and exported insrc/extensions/nodejs.ts), translating JS properties to$php_variables(PHPVariableinstances) and exposing methods and__invokefunctions transparently for full PHP interoperability. -
WordPress & MySQL Compatibility: Maintain full compatibility with WordPress database operations (
mysqli), installation flows, and theme/admin dashboard rendering tested against a local MySQL database. -
Case Insensitivity & Lowercase System Directive:
- Precompiled Transpilation: PHP identifiers (class names, function names, method names, namespace names, and constant references) are case-insensitive in PHP userland.
JSTranspilerMUST automatically convert all identifier keys, function calls, class lookups, method calls, namespace references, and constant references to lowercase at compile/transpilation time. - Zero Redundant
toLowerCase()at Runtime: To maximize runtime performance and minimize execution latency (low ms execution), internal engine/runtime methods (resolveClass,createObject,callMethod,callStaticMethod,getConstant,registerClass,registerFunction, etc.) MUST NOT perform redundant.toLowerCase()calls or regex searches during hot-path execution. All keys are pre-lowercased during AST transpilation. - Exposed PHP Userland Functions: Functions exposed directly to PHP userland that accept string identifier arguments at runtime (such as
define(),defined(),class_exists(),function_exists(),constant(),is_callable(),ini_get()) MUST convert user-supplied string parameters to lowercase when looking up engine/context maps. - Original Casing in Exception Messages: Error and exception messages (e.g.
Class "Foo\Bar" not found,Call to undefined static method Baz::qux()) MUST preserve the original casing as provided in PHP source code or user input.
- Precompiled Transpilation: PHP identifiers (class names, function names, method names, namespace names, and constant references) are case-insensitive in PHP userland.