Return an empty JSON object when an API promises a map
An API's settings field is a map when values exist, but becomes an array when empty. Some clients tolerate this; strongly typed clients often do not. In PHP, an empty array encodes as [], so the empty case needs an explicit representation when the contract requires {}.
Model the shape explicitly
<?php
$payload = ['settings' => (object) []];
assert(json_encode($payload, JSON_THROW_ON_ERROR) === '{"settings":{}}');
$payload = ['items' => []];
assert(json_encode($payload, JSON_THROW_ON_ERROR) === '{"items":[]}');
These fields express different concepts: named settings versus an ordered list of items. Avoid globally forcing all arrays to objects to fix one field. That can change unrelated list responses into maps with numeric string keys.
Make empty responses part of the schema
Document whether optional data is omitted, null, an empty map, or an empty list. Each choice has meaning. Omitted can mean not requested; null can mean unknown; an empty list can mean a known result with no members. A frontend should not have to infer those distinctions from inconsistent responses.
Test both populated and empty payloads. Check the serialized JSON, because a test that only inspects an intermediate PHP array can overlook the final encoding shape.
When adding new response fields, keep existing shapes stable or version the contract deliberately. A tiny server-side refactor from an object to an array may look harmless in PHP while breaking client deserialization. Treat the empty case as a first-class API example, not an edge case to fill in after the endpoint ships.
Reference
Official documentation. The examples here illustrate the stated boundary; adapt them to your application and test its failure paths.