Compiled class

Structure of the generated class#

PHP classes are compiled into corresponding CLR types. The sample below depicts a PHP class and the resulting CLR type decompiled into the C# language.

<?php
class X {
  function __construct() {
    // ...
  }
}
[PhpType("X", "index.php")]
public class X {

  // Reference to Context associated with the current instance.
  // Context is needed for most of PHP functions and PHP program lifecycle.
  protected readonly Context <ctx>;

  // Lazily instantiated array with dynamically added fields.
  internal PhpArray <runtime_fields>;

  // Constructor used internally to initialize the class without calling the `__construct` function.
  [EditorBrowsable(EditorBrowsableState.Never)]
  [CompilerGenerated, PhpFieldsOnlyCtor]
  protected internal X(Context <ctx>, QueryValue`1 _) : base() {
    this.<ctx> = <ctx>;
  }  
  // Regular class constructor.
  public X(Context <ctx>) : this(<ctx>) {
    __construct();
  }  
  // Context-less constructor to be used from other .NET languages.
  // Context is obtained or created for the current `ExecutionContext`.
  [CompilerGenerated, PhpHidden]
  public X() : this(ContextExtensions.CurrentContext) {
  }  
  // Compiled `__construct` function.
  public PhpValue __construct() {
    // ...
  }
}

Constructors#

The PHP class constructor is separated into several .ctor overloads as follows:

  • [PhpFieldsOnlyCtor] protected internal .ctor(Context, QueryValue``1)
    is an internally used constructor that initializes the instance without invoking the __construct() method. This is used when inheriting another PHP class, for object unserialization and when cloning. Note, the special QueryValue``1 parameter is here just to distinguish this internal .ctor and the regular .ctor.
  • .ctor(Context[, ... ctorparams])
    is used for the purposes of constructing a new instance of the object. .ctor() internally constructs the object, initializes fields and calls the proper PHP constructor if available.
  • .ctor([, ... ctorparams])
    is used by C# programs to create a new instance of the object. It is a wrapper of the .ctor above that does not require the instance of Context.
  • __construct([ctorparams])
    is an optional PHP constructor that might be called explicitly or as a part of .ctor.

In addition, the compiled PHP class contains .cctor() (static constructor) that initializes internal runtime descriptors and call sites.

Additional class members#

The class also contains the following fields used by both the compiler and runtime.

  • protected Context <ctx>
    holds the reference to the owning Context instance.
  • internal PhpArray <runtimeFields>
    holds dynamic class fields; is null by default.
  • IPhpCallable.Invoke(Context, PhpValue[])
    implementation of the IPhpCallable interface in case the class implements the magic __invoke function.
  • class __statics { ... }
    nested container for actual instances of PHP static fields. This is used by the runtime to manage different values of static fields for each Context (typically an HTTP Request).

Methods#

The declared class methods are compiled as corresponding CLR methods. The provided PHP type hints are respected and translated to the corresponding .NET type. Whenever the PHP type hint is missing, PhpValue type is used instead.

Optional parameters (those with an initial value) are translated to corresponding CLR (.NET) initial value metadata for those types that allow this. In case the initial value is an expression or anything not allowed as .NET [Optional], a function overload is automatically created.

Attributes#

The type is annotated with [PhpTypeAttribute]. The attribute contains a fully qualified PHP class name and relative file path where it was declared.

Remarks#

Every PHP class is bound to a Context. Internally every class is instantiated using a reference to an existing Context object. (This object is used for operations like echo and maintaining PHP options and request state).

It is possible to omit the Context instance; then keep in mind a new Context is created within the current ExecutionContext. In case of ASP.NET Core application, the Context is bound to the current HttpContext expecting the HttpContextAccessor service is registered.