* fix(compiler): preserve runtime class dispatch and introspection for polymorphic objects
When an object variable has an upper-bound declared type (e.g. assigned from
a function or method return), SSA marks it as a stable object. However,
stableObjects does not guarantee the concrete runtime class: the instance
may be a subclass at runtime, or null if nullable.
1. FuncCallOptimizer::genGetClassOptimized checked isStableObject($obj->name)
and folded get_class($obj) to the declared type literal string. For
$a = getAnimal() returning a Dog, get_class($a) was incorrectly folded
to "Animal" at compile time.
2. MethodCallTrait::parseStaticCall checked isStableObject($class) and
jumped to _do_call with the declared base class. For $a::who(), this
statically invoked Base::who() instead of dispatching to Dog::who() on
the runtime object.
Require proven exact object instances (exactObjects, populated from direct
new ConcreteClass() definitions) before folding get_class() or devirtualizing
static calls on object variables. Non-exact variables fall back to runtime
class resolution (php::fn::get_class() and php::callStaticMethod()),
matching PHP semantics.
Add unit test coverage verifying exact objects continue to fold/devirtualize
while polymorphic variables retain dynamic runtime dispatch.
* fix(compiler): preserve lexical scope in dynamic static calls and runtime type checks for get_class
- Use php::callScoped with getCallableScopeExpr() for dynamic static calls inside class methods to preserve caller visibility on protected methods
- Fall back to runtime php::call for get_class on non-exact values so nullable objects throw TypeError instead of dereferencing null
- Add behavioral PHPT tests for protected polymorphic static calls and nullable get_class
- Update unit tests for scoped dispatch and runtime introspection
* test(compiler): remove stray top-level main call from PHPT tests
In TypePHP AOT compilation, function main(): void serves as the binary
entrypoint. Top-level function calls outside a function are rejected by
the preprocessor as stray code.