Uh oh!
There was an error while loading. Please reload this page.
RFC: restrict Opia v1 dot access to arrays - #2
Conversation
Amospikins
commented
Aug 12, 2026
Thanks for this PR. I like the direction, especially the principle that Opia dot access should remain pure data access and should not accidentally invoke application behavior through PHP object semantics. Before merging, I want to clarify a few things so the RFC is very explicit about the boundary.
For example: finalreadonlyclass UserViewData
{
publicfunction__construct(
publicstring$name,
publicstring$email,
) {}
}Would this: ['user' => newUserViewData('Sanmi', 'sanmi@example.com')]make this invalid? My current understanding is yes, and only this should be valid: [
'user' => [
'name' => 'Sanmi',
'email' => 'sanmi@example.com',
],
]If that is the intention, I think the RFC should show both examples explicitly so there is no ambiguity.
If yes, I think that wording should probably become a first-class rule in the RFC because it is a strong and useful language guarantee.
For example, would this still be permitted: where If so, I think the RFC should make the distinction very clear:
For example: [
'user' => [
'profile' => [
'name' => 'Sanmi',
],
],
]I assume this remains valid: but this would fail as soon as any intermediate value is an object: [
'user' => [
'profile' => newProfileViewData(...),
],
]Is that the intended behavior?
For example, if the array contains: [
'first_name' => 'Sanmi',
]then: should fail rather than trying to infer I would prefer strict exact-key access.
For example: [
'users' => [
['name' => 'A'],
['name' => 'B'],
],
]Would: remain supported? If yes, I think the RFC should define clearly which key types are supported for indexed access.
I assume native arrays are the only structure intended for dot/index traversal in v1, while things like
Something explicit like: I think this would make the restriction much easier to understand in practice.
Was that separation part of the intended design, or is this purely a security restriction? If it is intentional, I think it is worth mentioning in the RFC because it explains why the restriction exists beyond just “objects are dangerous.”
For example, something like a future: interface OpiaData
{
publicfunctiontoOpiaData(): array;
}or another explicitly safe projection mechanism. I am not suggesting we add that now. I actually prefer keeping v1 array-only. I just want the RFC to make clear that future object support, if it ever exists, should be explicit and versioned rather than weakening the array-only rule later. Overall, I am positive on the proposal. The main thing I want before merging is for the RFC to make the valid and invalid boundaries extremely explicit, especially around simple readonly DTOs, nested values, registered functions, and the developer-facing error message. |
AyobamiH
commented
Aug 18, 2026
Thanks for the detailed review. Yes, your understanding matches the intended boundary, and I agree these rules should be made explicit in the RFC before merge.
Opia cannot access properties on PHP objects. It should include the offending path and type, but never the runtime value. The stable error code will be assigned through the separate error catalogue.
I’ll revise the RFC to make these valid and invalid boundaries explicit rather than leaving them implied. |
Summary
This PR proposes restricting Opia v1 dot-path traversal to arrays.
The current RFC permits reads from initialized, declared public properties while prohibiting magic access. That boundary no longer guarantees that a read is free of application-code execution. PHP 8.4 property hooks can execute arbitrary code during property access, while lazy objects may invoke an initializer or proxy factory when accessed.
Proposed contract
Dot access resolves exact string keys on arrays. Object dot access produces an unsupported-access error before the renderer performs property inspection or access.
Objects may cross registered-function boundaries, but this rule grants templates no direct property or index access to them.
Any future object-like traversal would require an explicit, versioned data-access contract that preserves Opia’s non-execution guarantee.
Rationale
Opia aims to prevent templates from executing arbitrary application code. Allowing property reads while trying to distinguish safe objects from hooked, magical, proxied, or lazy objects creates a runtime-dependent security boundary.
Array-only traversal gives version one a smaller and more deterministic contract. It is easier to implement consistently, test across supported PHP versions, and reason about during security review.
Scope
This PR changes only
docs/opia-language-rfc.md. It does not introduce or modify runtime code.Validation
The proposal was checked against the PHP documentation for property hooks and lazy-object initialization behavior.
Runtime tests were not run because this is an RFC-only change. The repository’s GitHub Actions workflow can still perform its standard PHP validation before merge.