PHP Type Casting

Type casting converts the value to a chosen type by writing the type within parentheses before the value to convert.

Scalars

Scalars (null, bool, int, float, string) and resources always become a single‑element array whose key is 0. null is the only type that becomes an empty array.

var_dump((array) null); // []
var_dump((array) true); // [true]
var_dump((array) 0); // [0]
var_dump((array) 3.15); // [3.15]
var_dump((array) 'Hello'); // ['Hello']
var_dump((array) '2.5'); // ['2.5]

Objects

Objects turn into associative arrays of their properties. Visibility matters:

  • Public → plain key.
  • Protected → key prefixed with "\0*\0".
  • Private → key prefixed with "\0ClassName\0".

Tests

<?php

declare(strict_types=1);

use PHPUnit\Framework\TestCase;

/**
 * Tests for PHP’s (array) cast behaviour.
 *
 * Each test method creates a value of a particular type,
 * casts it to an array, and asserts that the resulting
 * structure matches the specification in the reference table.
 */
final class CastToArrayTest extends TestCase
{
    /* ---------- Scalar ---------- */

    public function testNullBecomesEmptyArray(): void
    {
        $value = null;
        $this->assertSame([], (array) $value);
    }

    public function testTrueBecomesSingleElementArray(): void
    {
        $value = true;
        $this->assertSame([0 => true], (array) $value);
    }

    public function testFalseBecomesSingleElementArray(): void
    {
        $value = false;
        $this->assertSame([0 => false], (array) $value);
    }

    public function testIntZeroBecomesSingleElementArray(): void
    {
        $value = 0;
        $this->assertSame([0 => 0], (array) $value);
    }

    public function testIntPositiveBecomesSingleElementArray(): void
    {
        $value = 42;
        $this->assertSame([0 => 42], (array) $value);
    }

    public function testFloatZeroBecomesSingleElementArray(): void
    {
        $value = 0.0;
        $this->assertSame([0 => 0.0], (array) $value);
    }

    public function testFloatPositiveBecomesSingleElementArray(): void
    {
        $value = 3.14;
        $this->assertSame([0 => 3.14], (array) $value);
    }

    public function testFloatInfBecomesSingleElementArray(): void
    {
        $value = INF;
        $this->assertSame([0 => INF], (array) $value);
    }

    public function testFloatNanBecomesSingleElementArray(): void
    {
        $value = NAN;
        // NAN is not equal to itself, so we compare types and use is_nan()
        $result = (array) $value;
        $this->assertCount(1, $result);
        $this->assertArrayHasKey(0, $result);
        $this->assertIsFloat($result[0]);
        $this->assertTrue(is_nan($result[0]), 'Result should be NaN');
    }

    public function testEmptyStringBecomesSingleElementArray(): void
    {
        $value = '';
        $this->assertSame([0 => ''], (array) $value);
    }

    public function testNonEmptyStringBecomesSingleElementArray(): void
    {
        $value = 'foo';
        $this->assertSame([0 => 'foo'], (array) $value);
    }

    /* ---------- Resource ---------- */

    public function testResourceBecomesSingleElementArray(): void
    {
        $handle = fopen('php://temp', 'r');
        $this->assertIsResource($handle);

        $result = (array) $handle;

        // The resource is stored at index 0 – we don’t know its exact identifier,
        // so we just assert the type and count.
        $this->assertCount(1, $result);
        $this->assertArrayHasKey(0, $result);
        $this->assertIsResource($result[0]);

        fclose($handle);
    }

    /* ---------- Objects ---------- */

    public function testStdClassPublicProperties(): void
    {
        $obj = (object) ['a' => 1, 'b' => 2];
        $expected = ['a' => 1, 'b' => 2];
        $this->assertSame($expected, (array) $obj);
    }

    public function testObjectWithProtectedAndPrivateProperties(): void
    {
        $obj = new class {
            protected $prot = 5;
            private $priv = 7;
            public $pub = 9;
        };

        $cast = (array) $obj;

        // Expected keys according to PHP’s mangling rules
        $expected = [
            "\0*\0prot" => 5,               // protected
            "\0".__CLASS__."\0priv" => 7,   // private – classname is the anonymous class name
            'pub' => 9,                     // public
        ];

        // Because the anonymous class gets a generated name, we compute it dynamically:
        $privateKey = "\0".get_class($obj)."\0priv";
        $expected = [
            "\0*\0prot" => 5,
            $privateKey => 7,
            'pub' => 9,
        ];

        $this->assertSame($expected, $cast);
    }

    public function testNamedClassWithVisibilityModifiers(): void
    {
        $obj = new VisibilityDemo();
        $cast = (array) $obj;

        $expected = [
            "\0*\0protectedProp" => 'prot',
            "\0VisibilityDemo\0privateProp" => 'priv',
            'publicProp' => 'pub',
        ];

        $this->assertSame($expected, $cast);
    }
}

/**
 * Helper class used by the last two tests.
 *
class VisibilityDemo
{
    protected $protectedProp = 'prot';
    private $privateProp = 'priv';
    public $publicProp = 'pub';
}