PHP (8.5)
This assessment applies the coupling account — coupling as access to a shared resource, and the coupling floor [1], [2] — and the knowledge-embodiment theorem [3]; the language is assessed against its official reference [4].
1 Assessment
This page assesses PHP in five parts: core coupling — what the language’s own constructs force; ecosystem coupling — what the surrounding platform, tooling, and community cost; engineering readiness — whether the artifact can be reproduced, verified, observed, worked in quickly, connected to other languages, and governed openly; the profile — the unscored facts a score cannot express; and the scoring detail — the mechanism marks and the arithmetic behind every score. A ✅ bullet marks a construct that helps. A ⚠️ or ❌ bullet marks a cost; the scoring model does not price every cost named here.
Core coupling 28/100 · Ecosystem coupling 69/100 · Engineering readiness 84/100
1.1 Core coupling
1.1.1 Type
- ⚠️ Type declarations (PHP 7+): Gradual typing, improving
- ✅ Interfaces decouple: Can program to interfaces
- ❌ Weak typing historically: Type juggling couples
- ⚠️ Traits: Multiple inheritance-like, can couple
- ❌ Inconsistent stdlib:
strposvsstr_replacecouples to memorization - ✅ Namespaces scope every name: A namespace declaration qualifies a class, function, or constant, so two libraries can define the same short name
- ⚠️ Magic methods can hide coupling:
__get,__callobscure behavior
1.1.2 Construction
- ⚠️ Constructors can have side effects: No enforcement
- ❌ No immutability by default: Everything mutable
- ⚠️ Dependency injection available: Frameworks support it
- ❌ Global state tempting:
$_GET,$_POST,$_SESSIONcouple
1.1.3 Memory
- ✅ Reference counting: Immediate deallocation when references drop to zero
- ✅ Cycle collector: Detects and breaks circular references
- ✅ Request-scoped by default: Each request has isolated memory, cleared after request
- ❌ Long-running processes leak: Traditional PHP has no long-lived processes, but Swoole/ReactPHP do
- ✅ No manual memory management: Can’t have use-after-free in pure PHP
- ⚠️ Extensions can leak: C extensions may have memory issues
1.1.4 Error
- ❌ Exceptions unchecked: No type tracking
- ⚠️ Error vs Exception confusion: Two error mechanisms couple
- ❌
@operator suppresses errors: Hides coupling - ⚠️ Modern frameworks handle better: Laravel/Symfony impose discipline
1.1.5 Concurrency
- ❌ Shared-nothing by default: Each request is separate process
- ✅ Fibers (PHP 8.1): Built-in cooperative concurrency — enables async I/O without external extensions
- ⚠️ No built-in async event loop: Fibers need a framework (ReactPHP, Swoole) for full async; however Revolt/Amp provide fiber-based event loops
- ❌ Global state couples across requests: Sessions, databases
1.1.6 Platform
- ✅ No company owns the language: PHP is maintained by The PHP Group and released under the PHP Licence, a permissive BSD-style licence
- ✅ The reference implementation is free software: The Zend Engine is developed in the open and shipped by every Linux distribution
- ✅ The interpreter is portable: PHP runs on Linux, macOS, and Windows, under Apache, nginx through PHP-FPM, and IIS
- ✅ Commodity hosting provides it: Most shared hosts include a PHP runtime, so deployment needs no platform purchase
- ✅ No single distribution is required: Distribution packages, official builds, and vendor bundles run the same language
1.1.7 Trade-offs (not coupling)
- The language began as a page preprocessor: PHP grew from a templating tool, so markup and logic still share one file — a design origin whose cost is mixed presentation and behaviour
- Every variable carries a
$: The sigil marks a variable at a glance and cannot be omitted, a notation decision rather than a type-system one - The core library assumes one short request: Functions such as
header()andsession_start()act on the current request, an assumption that costs when the same code must run in a long-lived worker - Frameworks define the architecture: PSR interfaces and the Laravel or Symfony conventions shape practice more than the language does — an ecosystem convention, not a dependency the language forces
- Feature growth is version-gated: Enums, readonly classes, and property hooks arrive release by release, so the style a codebase may use follows its minimum supported version — an evolution cost, not a coupling
1.2 Ecosystem coupling
1.2.1 Performance
- ⚠️ Interpreted: Slower than compiled languages
- ✅ PHP 8+ JIT: Significant improvements for CPU-bound workloads
- ⚠️ Shared-nothing: Each request starts fresh (couples to memory)
- ✅ Fibers: Cooperative concurrency without process overhead
- ⚠️ OPcache helps: But couples deployment to caching
1.2.2 Ecosystem
- ✅ Composer: Good package manager
- ✅ Large ecosystem: Packagist has many packages
- ✅ Laravel, Symfony: Mature frameworks
- ✅ IDE support: PHPStorm excellent, VSCode good
- ⚠️ Quality varies: Many low-quality packages
1.2.3 Evolution
- ✅ Improving rapidly: PHP 8.1-8.5 added enums, fibers, readonly, property hooks, asymmetric visibility,
clone with, pipe operator - ✅ Regular releases: Yearly cadence
- ⚠️ Legacy burden: Must support old code (PHP 5.x still in the wild)
- ❌ Inconsistent stdlib: function_name vs functionName — PHP 8.x is standardizing but still inconsistent
1.2.4 Domain
- ✅ Excellent for traditional web: WordPress, Drupal, Laravel
- ⚠️ Backend only: Can’t do frontend (obviously)
- ✅ Fibers enable async: Modern PHP can do async I/O natively
- ⚠️ CLI possible: But uncommon relative to Python/Ruby
- ❌ No systems programming: Not suitable
1.2.5 Learning
- ✅ Very gentle: Easy to start
- ✅ Lots of resources: Tutorials, documentation
- ⚠️ Bad habits easy: Superglobals,
$prefix confusion - ✅ Quick productivity: Deploy immediately
1.2.6 Syntax
- ⚠️ C-like syntax: Familiar but verbose
- ✅ Property hooks (8.4): Eliminates getter/setter boilerplate
- ✅ Asymmetric visibility (8.4): Clean access control
- ❌ Superglobals:
$_GET,$_POSTeverywhere - ❌ Inconsistent stdlib: Hard to remember function names
1.2.7 Testing
- ✅ PHPUnit: Industry standard
- ⚠️ Xdebug: Works but setup needed
- ✅ Property hooks + readonly: Easier to test (less setup)
- ⚠️ Error reporting: Improving with strict types
1.2.8 Security
- ✅ Memory safe: GC prevents memory bugs
- ❌ SQL injection: Easy to do wrong (prepared statements help but not enforced)
- ❌ XSS: Template systems help but not enforced
- ❌ Superglobals: Injection attack surface
- ⚠️ Modern frameworks help: But not language-level
1.3 Engineering readiness
1.3.1 Reproducibility
- ❌ Builds are not byte-reproducible by default.
1.3.2 Supply chain
- ⚠️ Published packages carry no signed provenance by default.
1.3.3 Observability
- ✅ No charged mechanism in this dimension.
1.3.4 Feedback
- ✅ No charged mechanism in this dimension.
1.3.5 Interop
- ✅ No charged mechanism in this dimension.
1.3.6 Governance
- ✅ No charged mechanism in this dimension.
1.4 Profile
Unscored, and kept separate from every score on purpose. The profile records what a mechanism price cannot express: what a running program costs, how well a coding model and an agent work in the language, and whether a safety-critical path exists.
1.4.1 Energy and cost
What this axis asks: what does a running program cost in energy and time?
1.4.2 AI and agent readiness
What this axis asks: how well does a coding model and an agent work in this language?
1.4.3 Safety certification
What this axis asks: is there a certified or standards-qualified path to a safety-critical system?
- ⚠️ No certified or standards-qualified path for safety-critical systems.
1.5 Scoring detail
1.5.1 Core coupling Dimensions
| Dimension | Mechanism | Description | Present | Cost |
|---|---|---|---|---|
| Type | T1 |
dynamic no static check | ✅ | −15 |
T2 |
weak static | ✅ | −8 | |
T3 |
dynamic/duck dispatch | — | 0 | |
T4 |
no sum types | — | 0 | |
T5 |
no generics | ✅ | −4 | |
T6 |
no namespaces | — | 0 | |
T7 |
type erasure/reflection | — | 0 | |
T8 |
operator overloading | — | 0 | |
T9 |
inheritance required for polymorphism | — | 0 | |
T10 |
no null-safety | ✅ | −8 | |
T11 |
no module boundary | — | 0 | |
T12 |
no effect tracking | ✅ | −8 | |
T13 |
async/sync colouring | — | 0 | |
T14 |
unchecked foreign boundary | ✅ | −4 | |
| Type subtotal | −15 (−47) | |||
| Construction | C1 |
global mutable state by default | ✅ | −15 |
C2 |
no immutability by default | ✅ | −4 | |
C3 |
constructors coupled to allocation | — | 0 | |
C4 |
no constructor/validation | — | 0 | |
| Construction subtotal | −15 (−19) | |||
| Memory | M1 |
manual deallocation | — | 0 |
M2 |
GC non-deterministic pauses | — | 0 | |
M3 |
no RAII | ✅ | −4 | |
M4 |
no ownership model | ✅ | −8 | |
| Memory subtotal | −12 | |||
| Error | Er1 |
no structured path | — | 0 |
Er2 |
unchecked exceptions only | ✅ | −8 | |
Er3 |
errors ignored/non-exhaustive | ✅ | −4 | |
Er4 |
no composable result type | ✅ | −4 | |
| Error subtotal | −15 (−16) | |||
| Concurrency | K1 |
GIL/no parallel | ✅ | −15 |
K2 |
shared mutable state default | ✅ | −8 | |
K3 |
manual sync no race detection | ✅ | −8 | |
K4 |
no structured concurrency | — | 0 | |
K5 |
no primitives | — | 0 | |
| Concurrency subtotal | −15 (−31) | |||
| Platform | P1 |
cannot function outside one vendor/domain | — | 0 |
P2 |
single-vendor but other uses | — | 0 | |
P3 |
legacy/discontinued platform | — | 0 | |
| Platform subtotal | 0 |
Core Dimensions score: 28/100 — total cost = −72 (per-dimension subtotals are capped at −15; an uncapped cost is shown in parentheses where the cap bites).
1.5.2 Ecosystem coupling Dimensions
| Dimension | Mechanism | Description | Present | Cost |
|---|---|---|---|---|
| Performance | R1 |
interpreted no AOT/JIT | — | 0 |
R2 |
GC pauses | — | 0 | |
R3 |
JIT warmup | — | 0 | |
| Performance subtotal | 0 | |||
| Ecosystem | Ec1 |
no package manager | — | 0 |
Ec2 |
fragmented tooling | — | 0 | |
Ec3 |
small/niche/discontinued | — | 0 | |
Ec4 |
proprietary | — | 0 | |
Ec5 |
platform-locked tooling | — | 0 | |
Ec6 |
monoculture | ✅ | −8 | |
Ec7 |
legacy burden | — | 0 | |
| Ecosystem subtotal | −8 | |||
| Evolution | V1 |
breaking changes | — | 0 |
V2 |
frozen | — | 0 | |
V3 |
discontinued | — | 0 | |
V4 |
glacial standards | — | 0 | |
| Evolution subtotal | 0 | |||
| Domain | D1 |
domain/vendor lock-in | — | 0 |
D2 |
poor domain fit | — | 0 | |
D3 |
framework forces architecture | — | 0 | |
| Domain subtotal | 0 | |||
| Learning | L1 |
steep | — | 0 |
L2 |
large surface/multi-paradigm | — | 0 | |
L3 |
sparse docs | — | 0 | |
| Learning subtotal | 0 | |||
| Syntax | S1 |
verbose | — | 0 |
S2 |
inconsistent | ✅ | −8 | |
S3 |
punctuation-heavy | — | 0 | |
| Syntax subtotal | −8 | |||
| Testing | G1 |
weak tooling | — | 0 |
G2 |
poor debugging | — | 0 | |
G3 |
runtime-only errors | — | 0 | |
| Testing subtotal | 0 | |||
| Security | Q1 |
memory-unsafe | — | 0 |
Q2 |
dynamic/weak typing risk | ✅ | −8 | |
Q3 |
known vulnerability/injection | ✅ | −8 | |
| Security subtotal | −15 (−16) |
Meta Dimensions score: 69/100 — total cost = −31 (per-dimension subtotals are capped at −15; an uncapped cost is shown in parentheses where the cap bites).
1.5.3 Engineering readiness Dimensions
| Dimension | Mechanism | Description | Present | Cost |
|---|---|---|---|---|
| Reproducibility | Y1 |
build not reproducible | ✅ | −8 |
Y2 |
dependencies not pinned | — | 0 | |
| Reproducibility subtotal | −8 | |||
| Supply chain | Y3 |
no signed provenance | ✅ | −8 |
Y4 |
registry without namespacing | — | 0 | |
| Supply chain subtotal | −8 | |||
| Observability | Y5 |
no stable tracing standard | — | 0 |
Y6 |
no structured logging | — | 0 | |
| Observability subtotal | 0 | |||
| Feedback | Y7 |
slow build | — | 0 |
Y8 |
no fast in-editor analysis | — | 0 | |
| Feedback subtotal | 0 | |||
| Interop | Y9 |
no foreign-function interface | — | 0 |
Y10 |
no portable target | — | 0 | |
| Interop subtotal | 0 | |||
| Governance | Y11 |
single-vendor governance | — | 0 |
Y12 |
closed specification | — | 0 | |
| Governance subtotal | 0 |
Readiness Dimensions score: 84/100 — total cost = −16 (per-dimension subtotals are capped at −15; an uncapped cost is shown in parentheses where the cap bites).
Verdict: PHP is steadily improving its coupling profile. Enums (8.1), readonly classes (8.2), property hooks and asymmetric visibility (8.4) add compile-time structure. Fibers (8.1) enable built-in async. Superglobals create pervasive coupling. Shared-nothing architecture prevents temporal coupling but wastes resources. Main strength: simplicity for web, rapid improvement cadence. Main weakness: superglobals, inconsistent stdlib, no standard async runtime.
The formal development. The definitions, theorems, and proofs behind this page are published in:
- On the Nature of Coupling: All Coupling as Shared Resource Access — Zenodo, 2026 — doi:10.5281/zenodo.21925122
- Coupling as a Consequence of Cohesion: Decomposition, the Coupling Floor, and Domain-Imposed Coupling — Zenodo, 2026 — doi:10.5281/zenodo.21925201
- On the Nature of Cohesion: Cohesion as Correctness Relative to a Partitioning Rule — Zenodo, 2026 — doi:10.5281/zenodo.21703193