skip to content

In PHP, what is stdClass, and what does an (object) cast produce from an array, a scalar, null or an existing object?

level: middleimportance: should knowfreq 42%

answer

  1. generic class, not a universal parent
  2. exempt from the dynamic property deprecation
  3. array keys become properties, one level
  4. scalar lands in a property named scalar
  5. casting an object returns the same one

basics

~20 s

stdClass is PHP's empty built-in class for ad-hoc objects; it allows dynamic properties and is not a base class of other objects. (object) turns array keys into properties shallowly, wraps a scalar in ->scalar, and returns objects unchanged.

solid answer

~40 s

`stdClass` is a built-in class with no properties, methods or parent. It is **not** the root of PHP's class hierarchy, so `$quote instanceof stdClass` is false for your own classes. It is marked `#[\AllowDynamicProperties]`, so adding arbitrary properties stays legal after PHP 8.2 deprecated dynamic properties on ordinary classes. The `(object)` cast produces a `stdClass`: from an **array**, each top-level key becomes a property and nested arrays stay arrays (it is one level deep); integer keys become properties readable as `$o->{'0'}`. From a **scalar** you get a single property named `scalar`; from **null**, an empty `stdClass`; from an **existing object**, the same instance, unchanged and not copied. `json_decode()` also returns `stdClass` unless you ask for arrays. Being an object, a `stdClass` is shared by handle, unlike an array.

go deeper

for a junior

Recall that stdClass is a plain empty object and that (object) on an array turns its keys into properties.

for a middle

Explain the cast's edge cases: shallow conversion, the scalar property, same instance for objects, and the stdClass exemption from the dynamic property deprecation.

for a senior

Argue when a declared readonly class should replace stdClass or arrays at boundaries, and spot the handle-sharing difference between stdClass and arrays.

for a principal

Set a codebase policy on loose records versus declared data classes, weighing static analysis coverage against migration effort for legacy stdClass payloads.

## What stdClass is `stdClass` is PHP's **generic empty class**. It has no declared properties, no methods, no constructor arguments and no parent class. You create one with `new stdClass()` or with an `(object)` cast, and you give it properties by assigning them. Two misconceptions come from other languages: - It is **not** a universal base class. User classes do not extend it, so `$quote instanceof stdClass` is `false` unless the class explicitly extends `stdClass`. - It is not a special map type. It is an ordinary object with a property table, compared and copied like any other object. ## Dynamic properties and PHP 8.2 Assigning a property that a class does not declare creates a **dynamic property**. PHP 8.2 deprecated that for ordinary classes (`Creation of dynamic property Quote::$note is deprecated`), and classes that need it must opt in with `#[\AllowDynamicProperties]`. `stdClass` itself carries that attribute, so it stays the one built-in class where ad-hoc properties are silent and normal. Readonly classes never allow dynamic properties. ## The (object) cast, case by case | Source value | Result of `(object)` | |---|---| | array `['id' => 7, 'tags' => ['a']]` | `stdClass` with `->id` = 7 and `->tags` = the array `['a']` | | array with integer keys `[10, 20]` | `stdClass` with properties `"0"` and `"1"`, read as `$o->{'0'}` | | scalar `'draft'` | `stdClass` with one property `->scalar` = `'draft'` | | `null` | an empty `stdClass` | | an existing object | the **same instance**, unchanged | Three details are commonly missed: 1. The array cast is **shallow**. Only the top level becomes properties; `->tags` is still an array, not an object. 2. Integer keys are accessible with brace syntax since PHP 7.2; before that they were reachable only by iteration. 3. Casting an object does **not** copy it. `(object) $quote === $quote` is true. Use `clone` for a copy. The reverse cast, `(array) $object`, and its handling of private and protected property names belong to the type-juggling rules. ## stdClass versus an array The choice between an associative array and a `stdClass` for a loose record changes semantics, not just syntax: - **Copying** — an array is a value with copy-on-write; passing it to a function gives the function its own logical copy. A `stdClass` is shared by handle, so a function that sets `$row->total` changes the caller's object. - **Truthiness** — an empty array is `false` in a boolean context; an empty `stdClass` is `true`, like every object. - **Functions** — array functions (`array_map`, `count`, sorting) work on arrays, not on `stdClass`. - **Comparison** — two `stdClass` objects are `==` when their properties are loosely equal, and `===` only when they are the same instance. ## Reading properties that may be missing Because a `stdClass` has no declared shape, reading a property that was never set emits `Warning: Undefined property: stdClass::$note` and yields `null`. Defensive reads use `isset($row->note)`, `property_exists($row, 'note')` (true even when the value is `null`), or the null coalescing operator, `$row->note ?? 'n/a'`, which suppresses the warning. `foreach ($row as $name => $value)` walks the public properties in insertion order, and `get_object_vars($row)` returns them as an array when an array function is needed. ## Where it appears and what to prefer - `json_decode($json)` returns `stdClass` objects for JSON objects unless `$associative` is `true`. - Some database fetch modes return rows as `stdClass`. - Quick scripts and test fixtures use `(object) [...]` as a literal. For anything that crosses a function boundary in application code, a small **declared class** (often a readonly class with promoted properties) is better: typed properties, IDE completion and static analysis all work, and a typo in a property name fails instead of silently creating a new property.

  • Does `(object) $array` convert nested arrays into nested objects?
    No. The cast is one level deep: top-level keys become properties, and a value that is itself an array stays an array. To get nested objects you convert recursively yourself, or decode JSON without `$associative`, which builds a `stdClass` for every JSON object.
  • Why can you add properties to a `stdClass` without a deprecation notice in PHP 8.5?
    The PHP 8.2 deprecation applies to classes that do not opt in to dynamic properties. `stdClass` is declared with `#[\AllowDynamicProperties]`, so it keeps accepting arbitrary properties silently. A user class needs the same attribute to avoid `Creation of dynamic property ... is deprecated`.

saying these in an interview costs you the question

  • Every PHP class implicitly extends stdClass.
  • (object) on an array converts nested arrays into nested objects too.
  • (object) $obj returns a copy of the object.
  • Adding properties to stdClass is deprecated since PHP 8.2.
  • An empty stdClass is falsy, like an empty array.