Skip to content

CLR vs. PHP types#

This article provides information on how the runtime treats .NET types. As a result, with respect to this specification, it is possible to pass values between .NET (assuming C#) and PHP code implicitly, without the need of marshalling or additional conversions.

Type System#

The following table shows compatible .NET types and the corresponding PHP type:

.NET PHP PHP Features
PhpValue mixed
bool boolean
int, uint, long integer
double, float double
string, PhpString, byte[] string
object object ->
null NULL
PhpResource resource is_resource
PhpNumber integer|double
PhpArray, ArrayAccess, IList array, ArrayAccess []
Iterator, IteratorAggregate, IEnumerable iterable foreach, is_iterable
delegate, IPhpCallable, string, PhpArray(2) callable call_user_func, is_callable, etc.
Nullable<T> value|NULL isset, unset


Values can be read from and assigned to the Nullable<T> type. Any value of type Nullable<T> is treated as its contained value or NULL. An automatic conversion is performed. The operator isset is using the Nullable.HasValue property implicitly.

class Test {
    public int? Number;           // nullable field
    public double? Foo() { ... }; // return nullable from method
    public void Bar(bool? b) { }  // gets nullable parameter
$t = new Test;
$t->Number = 123; // assigns `new Nullable<int>(123)`
$t->Number = null; // assigns `default(Nullable<int>)`
isset( $t->Number ); // gets Number.HasValue
print_r( $t->Foo() ); // gets NULL or double
$t->Bar( NULL ); // passes `default(Nullable<bool>)` to the method
$t->Bar( true ); // passes `new Nullable<bool>(true)` to the method


PHP's concept of callables works with string pointing to a function name, array of two dimensions referring to a class and its method, classes with the __invoke method or instances of the Closure class. Variables of these types, denoted as callable, can be used for indirect calls as depicted in the sample below:

assert( is_callable($delegate) );
print_r( $delegate($arg1, $arg2) ); // $delegate is `callable`

PeachPie extends the set of callable types with any CLR delegate or objects implementing the IPhpCallable interface (Peachpie.Runtime.dll).

Sample C# code that passes a delegate to a PHP global variable:

mycontext.Globals["delegate"] = new Func<string, bool>( str => str.IsNormalized() );


The sample PHP code below is able to consume a variety of CLR objects in addition to PHP's array and Traversable.

foreach ($enumerable as $key => $value) { }

$enumerable may implement the following CLR interfaces:

  • IPhpEnumerable (Peachpie.Runtime.dll) is the extended version of IEnumerable. Objects implementing this interface are capable of being enumerated in PHP's foreach.
  • IDictionary; objects implementing this interface.
  • IEnumerable<(Key, Value)>; objects implementing IEnumerable<> of ValueTuple with two items.
  • IEnumerable<KeyValuePair<Key, Value>>; objects implementing IEnumerable<> of KeyValuePair<,>.
  • IEnumerable in general works with foreach as well. $key is auto-incremented starting with 0, $value is the current value of the enumerator.

As a result, standard .NET classes such as .NET arrays, ArrayList, List<>, Dictionary<,> or enumerators created using C# yield are transparently supported by PHP's foreach construct.

foreach by reference#

foreach ($enumerable as $key => &$value) { $value = 0; }
In order to support an iteration by reference, the enumerable object must return the value of type PhpAlias from the enumerator. Otherwise an exception of type InvalidOperationException is thrown.


PHP allows the accessing of an array and objects implementing ArrayAccess with square brackets [] as shown in the example below:

echo $list[10];

PeachPie provides the feature for System.Collections.IList, which allows consuming .NET arrays, Lists and other classes in PHP.