Darkwood · PHP architecture · 2026

Where Should Native Code Live?

Phalcon, Symfony, TrueAsync and Flow
at different layers of the stack

Framework
·
Application
·
Runtime
·
Orchestration
@matyo91

The context

A client architecture POC - a familiar dilemma.

The visible question

Should we migrate from Phalcon to Symfony?

The deeper question

Where should performance, boundaries, and workflows live?

High-traffic PHP platform · proven performance · growing workflow complexity · maintenance pressure.

01 | context @matyo91

The false debate

Phalcon vs Symfony vs TrueAsync

They are not direct competitors.

Different layers
Different constraints
Different tradeoffs

Framework choice is only part of the architecture.

02 | false-debate @matyo91

Three native layers

Each technology optimizes a different concern.

PhalconNative framework layer - MVC, router, ORM, cache
SymfonyApplication structure - DI, security, ecosystem, boundaries
TrueAsyncNative runtime - coroutines, async I/O, execution
03 | layers @matyo91

Phalcon

Phalcon was not a mistake.

C extension

Zephir/C · low overhead on the MVC path.

Read-heavy fit

Predictable latency · monolith APIs · cache-friendly.

Still maintained

v5.x active · releases in 2026 · ecosystem backers.

Valid choice

When MVC performance and team expertise still dominate.

04 | phalcon @matyo91

The shift

The optimization target changed.

Before

  • MVC bootstrap
  • Dispatch cost
  • Framework overhead

Now

  • I/O in workers
  • Multi-step workflows
  • Domain boundaries
  • Interop & hiring

Obsolete? Wrong question. What optimization matters now?

05 | optimization @matyo91

Architecture

Where should native code live?

flowchart TB
  subgraph orch [Orchestration layer]
    W[Workflows and pipelines]
  end
  subgraph app [Application layer]
    S[Symfony structure\nboundaries DI ecosystem]
  end
  subgraph fw [Framework layer]
    P[Phalcon native MVC]
  end
  subgraph rt [Runtime layer]
    T[TrueAsync ext-async\noptional execution]
  end
  Q[Where does complexity live?]
  Q --> orch
  Q --> app
  Q --> fw
  Q --> rt

Four independent decisions - not one migration checkbox.

06 | where-native @matyo91

Boundaries

Boundaries before frameworks.

Many migrations fail because the container changes - not the domain.

Bounded contexts
Domain vs application services
CQRS / read models
Eventual consistency

Redraw boundaries first. Framework second.

07 | boundaries @matyo91

Archetype · PEFT

Read-heavy editorial platform pattern.

flowchart LR
  IN[Ingestion] --> PUB[Publication]
  PUB --> STORE[(Canonical store)]
  PUB --> INV[Invalidation]
  INV --> RM[Read models]
  RM --> API[Read APIs]
Event-driven
Derived views
Cache-heavy read path
08 | peft @matyo91

Orchestration

Frameworks excel at request → response.

Mature systems exceed that cycle.

Validate
→
Persist
→
Invalidate
→
Rebuild
→
Emit

Multi-step workflows need a first-class architectural place.

09 | orchestration @matyo91

Flow

Same workflow. Interchangeable execution.

DriverInterface - business logic stable, execution model changes.

Fiber default
Amp
ReactPHP
Swoole
TrueAsync experimental
$flow = (new Flow(job: new Validate(), driver: $driver))
    ->fn(new Persist())
    ->fn(new RebuildReadModel());

Flow explores orchestration as an architectural primitive - not a framework replacement.

10 | flow @matyo91

Paths

Four credible outcomes - none is default.

01Stay on Phalcon · modernize incrementally
02Migrate to Symfony · ecosystem & structure
03Hybrid · coexistence with clear API contracts
04Runtime async · independent of web framework
11 | paths @matyo91

Anti-patterns

What not to do.

  • Migrate by reflex - when SLOs and team fit are fine
  • Put async everywhere - TrueAsync is experimental, opt-in only
  • Change framework without redrawing boundaries
  • Confuse framework migration with workflow design
  • Turn Flow into a framework for every feature
12 | anti-patterns @matyo91

Conclusion

Framework choice still matters.

The deeper questions:

Workflows

Where do multi-step pipelines live?

Boundaries

Where does domain end and coordination begin?

Orchestration

Who owns execution strategy?

Native code distributes across the stack.

13 | conclusion @matyo91