<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ilyas Deckers</title>
    <description>The latest articles on DEV Community by Ilyas Deckers (@ilyasdeckers).</description>
    <link>https://dev.to/ilyasdeckers</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2971045%2F1c9d2dd2-36ac-48c3-9e63-ec2e1e771371.png</url>
      <title>DEV Community: Ilyas Deckers</title>
      <link>https://dev.to/ilyasdeckers</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ilyasdeckers"/>
    <language>en</language>
    <item>
      <title>PHP + Static Analysis vs. Native Statically Typed Languages</title>
      <dc:creator>Ilyas Deckers</dc:creator>
      <pubDate>Thu, 17 Apr 2025 09:26:07 +0000</pubDate>
      <link>https://dev.to/ilyasdeckers/php-static-analysis-vs-native-statically-typed-languages-57d2</link>
      <guid>https://dev.to/ilyasdeckers/php-static-analysis-vs-native-statically-typed-languages-57d2</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Modern software development increasingly emphasizes code robustness, maintainability, and catching errors early. Type safety plays a crucial role in achieving these goals. PHP teams often face a choice: migrate to a language with built-in static typing or enhance their existing dynamically typed language (like PHP) with powerful static analysis tools.&lt;/p&gt;

&lt;p&gt;This article compares these two approaches:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Native Statically Typed Languages:&lt;/strong&gt; Languages where type checking is a fundamental, mandatory part of the compiler (e.g., Go, C#, Rust, C++, Java, TypeScript*).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;PHP + Static Analysis Tools:&lt;/strong&gt; Using PHP (which is dynamically typed at its core) augmented with tools like PHPStan or Psalm to perform type checking before runtime.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;(*Note: TypeScript compiles to JavaScript but provides static typing during development and compilation).&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Approach 1: Native Statically Typed Languages
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Definition
&lt;/h3&gt;

&lt;p&gt;These languages require type information to be known at compile time. The compiler rigorously checks type compatibility throughout the codebase before producing an executable or intermediate code.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Examples: Go, C#, Rust, Scala, Java)&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Mechanism
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Type checking is &lt;strong&gt;inherent to the language and compiler&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;It's a &lt;strong&gt;mandatory step&lt;/strong&gt; to produce a runnable program.&lt;/li&gt;
&lt;li&gt;Errors found by the compiler &lt;strong&gt;prevent compilation&lt;/strong&gt; altogether.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pros
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Strong Compile-Time Guarantees:&lt;/strong&gt; Catches a wide range of type errors, null pointer issues (depending on language features like null safety), and API contract violations &lt;em&gt;before&lt;/em&gt; the code can even run.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High Runtime Safety:&lt;/strong&gt; The compiled code benefits from the guarantees established at compile time, leading to fewer unexpected runtime type errors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Excellent Refactoring Safety:&lt;/strong&gt; The compiler immediately flags issues arising from code changes (e.g., changing a function signature).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance Potential:&lt;/strong&gt; Type information allows compilers to perform significant optimizations (Ahead-of-Time compilation), often leading to better runtime performance compared to interpreted languages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clear Contracts:&lt;/strong&gt; Types serve as enforced documentation, making interfaces and data structures explicit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rich Native Type Systems:&lt;/strong&gt; Often include advanced features like generics, interfaces, traits, enums, etc., as core language constructs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mature Tooling &amp;amp; IDE Support:&lt;/strong&gt; Excellent code completion, error highlighting, and refactoring tools based directly on the language's type system.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Steeper Learning Curve:&lt;/strong&gt; Requires learning a new language syntax, standard library, ecosystem, build tools, and potentially different programming paradigms (e.g., Go's concurrency, Rust's ownership).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Migration Effort:&lt;/strong&gt; Moving an existing PHP codebase requires a significant rewrite.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Initial Strictness:&lt;/strong&gt; Can feel less flexible or more verbose initially compared to dynamic languages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compilation Time:&lt;/strong&gt; Can be a factor in development cycles for very large projects (though often offset by finding errors earlier).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Approach 2: PHP + Static Analysis Tools
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Definition
&lt;/h3&gt;

&lt;p&gt;This involves writing standard PHP code, leveraging its native type hinting features (scalar types, return types, property types, union types, etc.), and potentially adding detailed PHPDoc annotations. External tools then analyze this code &lt;em&gt;without running it&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Examples: PHP with PHPStan or Psalm)&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Mechanism
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Type checking is performed by an &lt;strong&gt;external tool&lt;/strong&gt;, separate from the PHP interpreter itself.&lt;/li&gt;
&lt;li&gt;It analyzes code based on native type hints (&lt;code&gt;int&lt;/code&gt;, &lt;code&gt;string&lt;/code&gt;, &lt;code&gt;?User&lt;/code&gt;, &lt;code&gt;int|string&lt;/code&gt;) and detailed PHPDoc annotations (&lt;code&gt;@var&lt;/code&gt;, &lt;code&gt;@param&lt;/code&gt;, &lt;code&gt;@return&lt;/code&gt;, &lt;code&gt;@template&lt;/code&gt;, &lt;code&gt;array{...}&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Analysis is typically run manually, via commit hooks, or in a CI/CD pipeline. It &lt;strong&gt;does not prevent&lt;/strong&gt; PHP from &lt;em&gt;attempting&lt;/em&gt; to run code with type errors if the analysis step is skipped.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pros
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Familiar Ecosystem:&lt;/strong&gt; Allows teams to stay within the PHP language, leveraging existing knowledge, frameworks (Laravel, Symfony, etc.), libraries, and infrastructure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lower Initial Learning Curve:&lt;/strong&gt; Focuses on learning the static analysis tool and writing better-typed PHP, rather than an entirely new language.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gradual Adoption:&lt;/strong&gt; Tools like PHPStan/Psalm have configurable levels and baseline features, allowing teams to introduce type checking incrementally, focusing on new code first if needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Catches Most Type Errors:&lt;/strong&gt; When configured well and used diligently, these tools catch a vast majority of type-related errors, nullability issues, and other potential bugs before runtime.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improved Code Quality:&lt;/strong&gt; Significantly enhances PHP code's readability, maintainability, and reliability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Safer Refactoring within PHP:&lt;/strong&gt; Provides much greater confidence when making changes to existing PHP code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Excellent IDE Integration:&lt;/strong&gt; Plugins provide real-time feedback directly in the editor (VS Code, PhpStorm).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No Runtime Guarantee:&lt;/strong&gt; PHP's core execution model remains dynamically typed. If the static analysis step is skipped, incomplete, or if external dependencies violate contracts in unexpected ways, &lt;strong&gt;runtime type errors are still possible&lt;/strong&gt;. The guarantee comes from the &lt;em&gt;process&lt;/em&gt; of using the tool, not the language runtime itself.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dependency on Tooling &amp;amp; Annotations:&lt;/strong&gt; The effectiveness relies heavily on the quality of type hints, the thoroughness of PHPDoc annotations (especially for generics or complex array shapes), and the configuration level of the analysis tool.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Potential Verbosity (PHPDoc):&lt;/strong&gt; Complex type scenarios might require verbose PHPDoc blocks where native PHP types are insufficient. (PHP continues to improve its native type system, reducing this over time).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analysis Time:&lt;/strong&gt; Can add time to CI builds or pre-commit checks for large projects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No Inherent Performance Gain:&lt;/strong&gt; Does not fundamentally change PHP's runtime performance characteristics (unlike compilation in many static languages).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Key Differences Summarized
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Native Static Language (Go, C#, Rust...)&lt;/th&gt;
&lt;th&gt;PHP + Static Analysis (PHPStan/Psalm)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Core Nature&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Statically Typed&lt;/td&gt;
&lt;td&gt;Dynamically Typed (at runtime)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Enforcement By&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Compiler (Built-in, Mandatory)&lt;/td&gt;
&lt;td&gt;External Tool (Process-driven)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Error Detection&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Compile-Time&lt;/td&gt;
&lt;td&gt;Analysis-Time (Pre-Runtime)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Runtime Safety&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Very High (Language Guarantee)&lt;/td&gt;
&lt;td&gt;High (If analysis is run &amp;amp; complete)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Type System Used&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Native Language Features&lt;/td&gt;
&lt;td&gt;Native PHP Types + PHPDoc Annotations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Performance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Often Higher (AOT Optimizations)&lt;/td&gt;
&lt;td&gt;Standard PHP Performance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Learning Curve&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Higher (New Language/Ecosystem)&lt;/td&gt;
&lt;td&gt;Lower (Enhance Existing Skills)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Adoption Scope&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Full Language Switch&lt;/td&gt;
&lt;td&gt;Incremental / Gradual Possible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Flexibility&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Lower (Compiler Strictness)&lt;/td&gt;
&lt;td&gt;Higher (PHP Core Dynamism)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  When to Choose Which Approach?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Choose Native Static Languages if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Performance, concurrency, or compile-time memory safety are top priorities.&lt;/li&gt;
&lt;li&gt;Starting a new project where the team is willing and able to learn a new ecosystem.&lt;/li&gt;
&lt;li&gt;The specific strengths of a language align well with the project domain (e.g., systems work for Rust, high-concurrency services for Go, large enterprise apps for C#/Java).&lt;/li&gt;
&lt;li&gt;You require the strongest possible &lt;em&gt;runtime&lt;/em&gt; guarantees enforced by the language itself.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Choose PHP + Static Analysis if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need to improve the quality and maintainability of an existing PHP codebase.&lt;/li&gt;
&lt;li&gt;Your team wants to remain within the PHP ecosystem (frameworks, libraries, developer skills).&lt;/li&gt;
&lt;li&gt;A lower initial learning curve and gradual adoption are preferred.&lt;/li&gt;
&lt;li&gt;You value PHP's flexibility and rapid development cycle but want significantly increased safety.&lt;/li&gt;
&lt;li&gt;You accept that the ultimate runtime safety relies on the &lt;em&gt;process&lt;/em&gt; of using the tools correctly, rather than being inherent in the PHP runtime itself.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Both approaches offer significant advantages over traditional, untyped dynamic language development. Native statically typed languages provide the strongest compile-time and runtime guarantees at the cost of a higher learning curve and migration effort. Enhancing PHP with powerful static analysis tools like PHPStan or Psalm offers a pragmatic path to achieving vastly improved type safety, code quality, and maintainability while leveraging existing skills and ecosystems, making it an excellent choice for many PHP teams.&lt;/p&gt;

</description>
      <category>php</category>
      <category>programming</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>Single Action Handlers in PHP Frameworks</title>
      <dc:creator>Ilyas Deckers</dc:creator>
      <pubDate>Thu, 17 Apr 2025 07:51:24 +0000</pubDate>
      <link>https://dev.to/ilyasdeckers/single-action-handlers-in-php-frameworks-3jai</link>
      <guid>https://dev.to/ilyasdeckers/single-action-handlers-in-php-frameworks-3jai</guid>
      <description>&lt;h2&gt;
  
  
  Introduction: What is the Single Action Handler Pattern?
&lt;/h2&gt;

&lt;p&gt;In modern PHP web development, the &lt;strong&gt;Single Action Handler&lt;/strong&gt; (often implemented as an &lt;strong&gt;Invokable Controller&lt;/strong&gt; or specifically as a &lt;strong&gt;PSR-15 Request Handler&lt;/strong&gt;) represents a shift towards more focused, decoupled, and testable code, especially for APIs and specific web actions.&lt;/p&gt;

&lt;p&gt;This pattern moves away from traditional Model-View-Controller (MVC) structures where a single Controller class might handle numerous related routes via multiple methods (e.g., &lt;code&gt;UserController&lt;/code&gt; with &lt;code&gt;index()&lt;/code&gt;, &lt;code&gt;show()&lt;/code&gt;, &lt;code&gt;store()&lt;/code&gt;, etc.).&lt;/p&gt;

&lt;p&gt;Instead, a &lt;strong&gt;Single Action Handler is a class dedicated exclusively to processing the logic for one specific route or endpoint.&lt;/strong&gt; It achieves this typically through:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Implementing PHP's magic &lt;code&gt;__invoke()&lt;/code&gt; method, allowing the class instance to be treated as the action itself.&lt;/li&gt;
&lt;li&gt; Implementing the &lt;code&gt;Psr\Http\Server\RequestHandlerInterface&lt;/code&gt;, which defines a &lt;code&gt;handle(ServerRequestInterface $request): ResponseInterface&lt;/code&gt; method – the standard defined by PSR-15.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This article explores this pattern, its benefits, the crucial role of PSR standards, and how it can be implemented effectively (and with varying degrees of native support) in popular PHP frameworks like Mezzio, Symfony, and Laravel.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Traditional Multi-Action Controller:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// UserController.php&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserController&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// ... other methods ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// routes.php&lt;/span&gt;
&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/users/{id}'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;UserController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'show'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/users'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;UserController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'store'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Single Action Handler Pattern (Conceptual):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ShowUserAction.php (or ShowUserController.php)&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ShowUserAction&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="cm"&gt;/* Logic for showing a user */&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// StoreUserAction.php (or StoreUserController.php)&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StoreUserAction&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="cm"&gt;/* Logic for storing a user */&lt;/span&gt; 
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// routes.php&lt;/span&gt;
&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/users/{id}'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ShowUserAction&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/users'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;StoreUserAction&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why Use This Pattern? The Rationale
&lt;/h2&gt;

&lt;p&gt;Adopting the single action handler pattern brings significant advantages:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Single Responsibility Principle (SRP):&lt;/strong&gt; Each class does exactly one thing. This drastically improves clarity, making code easier to understand, modify safely, and debug.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Enhanced Testability:&lt;/strong&gt; Unit testing becomes much simpler. Smaller classes have fewer dependencies to mock, and the scope of each test is clearly defined.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Improved Organization:&lt;/strong&gt; Prevents "fat controllers." Code can be neatly organized by feature or domain slice, leading to a more maintainable structure, especially in large applications.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Increased Readability:&lt;/strong&gt; The class name itself often describes the action (e.g., &lt;code&gt;ProcessPaymentHandler&lt;/code&gt;, &lt;code&gt;GetUserApiEndpoint&lt;/code&gt;). The single &lt;code&gt;handle()&lt;/code&gt; or &lt;code&gt;__invoke()&lt;/code&gt; method contains all relevant logic.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Precise Dependency Management:&lt;/strong&gt; Only dependencies needed for that &lt;em&gt;specific action&lt;/em&gt; are injected, leading to cleaner constructors and more efficient resource usage.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Reduced Cognitive Load:&lt;/strong&gt; Developers can focus entirely on the task of a single endpoint without the mental overhead of unrelated actions in the same file.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Importance of PSR Standards For single Action Handles
&lt;/h2&gt;

&lt;p&gt;Understanding PSR (PHP Standard Recommendations) is crucial for appreciating the full benefits of modern PHP development and patterns like PSR-15 Request Handlers. PSRs are specifications published by the PHP Framework Interop Group (PHP-FIG), comprised of members from various major PHP projects. Their goal is to promote &lt;strong&gt;interoperability&lt;/strong&gt; and &lt;strong&gt;standardization&lt;/strong&gt; across the PHP ecosystem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key PSRs for Web Development:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PSR-7 (HTTP Message Interfaces):&lt;/strong&gt; Defines standard interfaces for HTTP request (&lt;code&gt;RequestInterface&lt;/code&gt;, &lt;code&gt;ServerRequestInterface&lt;/code&gt;) and response (&lt;code&gt;ResponseInterface&lt;/code&gt;) objects, along with related objects like URIs and streams. A key feature is &lt;strong&gt;immutability&lt;/strong&gt;, which prevents unexpected side effects when messages are passed through multiple layers (like middleware).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PSR-15 (HTTP Server Request Handlers &amp;amp; Middleware):&lt;/strong&gt; Builds upon PSR-7.

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;RequestHandlerInterface&lt;/code&gt;: Defines a standard way to process a PSR-7 request and return a PSR-7 response (our Single Action Handler!).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;MiddlewareInterface&lt;/code&gt;: Defines a standard interface for middleware components that process requests &lt;em&gt;before&lt;/em&gt; or &lt;em&gt;after&lt;/em&gt; a handler (or other middleware).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why Adhering to PSR Standards (like PSR-7/15) is a Good Idea:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Interoperability:&lt;/strong&gt; This is the primary driver. Code written against PSR interfaces (handlers, middleware, HTTP clients, factories) can often be used across different frameworks and libraries that also adhere to those standards. You can mix and match components from different vendors.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Reduced Vendor Lock-In:&lt;/strong&gt; By relying on community standards rather than framework-specific abstractions for core functionalities like HTTP handling, your application becomes less tied to a single framework's ecosystem, making future migrations or integrations potentially easier.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Reusability:&lt;/strong&gt; Logic encapsulated in PSR-15 handlers or middleware can be more easily reused across different projects, even if those projects use different underlying frameworks (provided they support PSR-15).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Consistency &amp;amp; Predictability:&lt;/strong&gt; Standard interfaces mean developers encounter familiar patterns across different projects and libraries. This reduces the learning curve and makes codebases easier to understand and contribute to.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Modern Best Practices:&lt;/strong&gt; PSR-7's immutability and PSR-15's clear definition of middleware and handlers encourage decoupled, layered application design, which is widely considered a best practice for building robust web applications.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Future-Proofing:&lt;/strong&gt; Basing core application logic on community-agreed standards makes it less vulnerable to breaking changes within a specific framework's internal abstractions.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Easier Package Development:&lt;/strong&gt; If you're creating reusable packages (e.g., authentication middleware, API validation logic), targeting PSR interfaces makes them instantly usable in a much wider range of applications.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Relevance to Handlers:&lt;/strong&gt; Using PSR-15 &lt;code&gt;RequestHandlerInterface&lt;/code&gt; directly ties your core request-handling logic to these community standards, unlocking the benefits of interoperability, reusability, and consistency. Frameworks that embrace these standards natively often provide a smoother path to achieving these advantages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation Across Frameworks
&lt;/h2&gt;

&lt;p&gt;Frameworks vary in their native support for PSR-15 handlers.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PSR-15 Native Frameworks (e.g., Mezzio):&lt;/strong&gt; Use PSR-15 handlers as the fundamental way to process requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Full-Stack Frameworks (e.g., Symfony, Laravel):&lt;/strong&gt; Primarily use their own abstractions but provide mechanisms (bridges, extension points) to integrate PSR-15 handlers, requiring varying levels of effort.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  1. Middleware Frameworks (PSR-15 Native - Mezzio Example)
&lt;/h3&gt;

&lt;p&gt;Frameworks like Mezzio (formerly Zend Expressive) are built &lt;em&gt;from the ground up&lt;/em&gt; around PSR-7 and PSR-15. Using single-action &lt;code&gt;RequestHandlerInterface&lt;/code&gt; implementations is the standard, idiomatic way.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Core Concept:&lt;/strong&gt; Requests flow through a PSR-15 middleware pipeline, ending at a route-specific &lt;code&gt;RequestHandlerInterface&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Example Implementation (Mezzio):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="c1"&gt;// src/App/Handler/GetUserHandler.php&lt;/span&gt;
&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Handler&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Repository\UserRepositoryInterface&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Laminas\Diactoros\Response\JsonResponse&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Psr\Http\Message\ResponseInterface&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Psr\Http\Message\ServerRequestInterface&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Psr\Http\Server\RequestHandlerInterface&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GetUserHandler&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;RequestHandlerInterface&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;UserRepositoryInterface&lt;/span&gt; &lt;span class="nv"&gt;$userRepository&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;UserRepositoryInterface&lt;/span&gt; &lt;span class="nv"&gt;$userRepository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;userRepository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$userRepository&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ServerRequestInterface&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;ResponseInterface&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Get route parameter (assuming router middleware added it as attribute)&lt;/span&gt;
        &lt;span class="nv"&gt;$userId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;userRepository&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;findById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;JsonResponse&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'error'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'User not found'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Assuming User object has a suitable method for array conversion&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;JsonResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;toArray&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Routing (e.g., in &lt;code&gt;config/routes.php&lt;/code&gt;)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;```php
$app-&amp;gt;get('/api/users/{id:\d+}', App\Handler\GetUserHandler::class, 'api.user.get');
```
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pros (Mezzio/PSR-15 Native):&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pure PSR Adherence:&lt;/strong&gt; Natively uses PSR-7/15, maximizing interoperability and benefits of the standards. No bridging needed for core HTTP handling.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Minimalism &amp;amp; Performance:&lt;/strong&gt; Very lean core, potentially high performance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maximum Flexibility &amp;amp; Decoupling:&lt;/strong&gt; Full control over components; promotes decoupled design.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Cons (Mezzio/PSR-15 Native):&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;More Initial Setup:&lt;/strong&gt; Requires assembling the application stack (router, container, ORM, etc.).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Smaller Framework-Specific Ecosystem:&lt;/strong&gt; Fewer Mezzio-specific bundles compared to Symfony/Laravel (though any standard PHP/PSR package works).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Symfony: Achieving PSR-15 Compliance
&lt;/h3&gt;

&lt;p&gt;Symfony is highly flexible and &lt;em&gt;can&lt;/em&gt; work cleanly with PSR-15 handlers, though its core uses &lt;code&gt;HttpFoundation&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Option 1: Adapter Pattern (The Basic Approach)&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Concept:&lt;/strong&gt; Create a standard Symfony controller (&lt;code&gt;__invoke&lt;/code&gt;) that acts as a bridge. It receives the &lt;code&gt;HttpFoundation\Request&lt;/code&gt;, converts it to PSR-7 &lt;code&gt;ServerRequestInterface&lt;/code&gt; (using &lt;code&gt;symfony/psr-http-message-bridge&lt;/code&gt;), calls your actual &lt;code&gt;RequestHandlerInterface&lt;/code&gt;, converts the PSR-7 &lt;code&gt;ResponseInterface&lt;/code&gt; back to &lt;code&gt;HttpFoundation\Response&lt;/code&gt;, and returns it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pros:&lt;/strong&gt; Explicit, relatively easy to understand for a single handler.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cons:&lt;/strong&gt; &lt;strong&gt;Significant boilerplate&lt;/strong&gt; - requires one adapter class per PSR-15 handler. Feels cumbersome.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Example:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Controller\Api\Orders&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Handler\ProcessOrderHandler&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Symfony\Bridge\PsrHttpMessage\HttpFoundationFactoryInterface&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Symfony\Component\HttpFoundation\Request&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Symfony Request&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Symfony\Component\HttpFoundation\Response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Symfony Response&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Symfony\Component\Routing\Annotation\Route&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProcessOrderAdapterAction&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;HttpMessageFactoryInterface&lt;/span&gt; &lt;span class="nv"&gt;$psrHttpFactory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;HttpFoundationFactoryInterface&lt;/span&gt; &lt;span class="nv"&gt;$httpFoundationFactory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;ProcessOrderHandler&lt;/span&gt; &lt;span class="nv"&gt;$handler&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="kt"&gt;HttpMessageFactoryInterface&lt;/span&gt; &lt;span class="nv"&gt;$psrHttpFactory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="kt"&gt;HttpFoundationFactoryInterface&lt;/span&gt; &lt;span class="nv"&gt;$httpFoundationFactory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="kt"&gt;ProcessOrderHandler&lt;/span&gt; &lt;span class="nv"&gt;$handler&lt;/span&gt; &lt;span class="c1"&gt;// Autowired by Symfony DI&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;psrHttpFactory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$psrHttpFactory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;httpFoundationFactory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$httpFoundationFactory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$handler&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="na"&gt;#[Route('/api/orders', name: 'api_order_process', methods: ['POST'])]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;Response&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// 1. Convert Symfony Request -&amp;gt; PSR-7 Request&lt;/span&gt;
        &lt;span class="nv"&gt;$psrRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;psrHttpFactory&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;createRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// 2. Call the actual PSR-15 Handler&lt;/span&gt;
        &lt;span class="nv"&gt;$psrResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$psrRequest&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// 3. Convert PSR-7 Response -&amp;gt; Symfony Response&lt;/span&gt;
        &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;httpFoundationFactory&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;createResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$psrResponse&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// 4. Return Symfony Response&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Option 2: Centralized Listener (The Cleaner Approach)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Concept:&lt;/strong&gt; Leverage Symfony's Kernel Events. Create an Event Listener for the &lt;code&gt;kernel.controller&lt;/code&gt; event. This listener checks if the controller resolved by the router implements &lt;code&gt;RequestHandlerInterface&lt;/code&gt;. If it does, the listener takes over: it uses the PSR-7 bridge to convert the request, executes the handler's &lt;code&gt;handle&lt;/code&gt; method, converts the response back, and sets it directly on the event (&lt;code&gt;$event-&amp;gt;setResponse()&lt;/code&gt;), bypassing Symfony's standard controller execution.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Detailed Steps:&lt;/strong&gt;

&lt;ol&gt;
&lt;li&gt; Install bridge: &lt;code&gt;composer require symfony/psr-http-message-bridge nyholm/psr7&lt;/code&gt; (Nyholm is a popular PSR-7 implementation).&lt;/li&gt;
&lt;li&gt; Create your PSR-15 handler class (implementing &lt;code&gt;RequestHandlerInterface&lt;/code&gt;). Ensure it's registered as a service.&lt;/li&gt;
&lt;li&gt; Create an Event Listener class implementing &lt;code&gt;EventSubscriberInterface&lt;/code&gt; or listening to &lt;code&gt;KernelEvents::CONTROLLER&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt; Inject &lt;code&gt;HttpMessageFactoryInterface&lt;/code&gt; and &lt;code&gt;HttpFoundationFactoryInterface&lt;/code&gt; (from the bridge) into the listener.&lt;/li&gt;
&lt;li&gt; In the listener method:

&lt;ul&gt;
&lt;li&gt;Get controller from &lt;code&gt;$event-&amp;gt;getController()&lt;/code&gt;. Check if it implements &lt;code&gt;RequestHandlerInterface&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If yes: Convert &lt;code&gt;$event-&amp;gt;getRequest()&lt;/code&gt; -&amp;gt; PSR-7 Request.&lt;/li&gt;
&lt;li&gt;Call &lt;code&gt;$controller-&amp;gt;handle($psr7Request)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Convert PSR-7 Response -&amp;gt; Symfony Response.&lt;/li&gt;
&lt;li&gt;Call &lt;code&gt;$event-&amp;gt;setResponse($symfonyResponse)&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt; Register the listener with appropriate priority.&lt;/li&gt;

&lt;li&gt; Route directly to the service ID or FQCN of your PSR-15 handler class.&lt;/li&gt;

&lt;/ol&gt;

&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Pros:&lt;/strong&gt; &lt;strong&gt;Eliminates adapter boilerplate.&lt;/strong&gt; Centralizes bridging logic. Allows clean routing directly to PSR-15 handlers. Promotes PSR standard usage cleanly within Symfony.&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Cons:&lt;/strong&gt; Requires deeper understanding of Symfony's Kernel Events. The listener becomes a critical piece of infrastructure that needs careful testing.&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Overall Symfony &amp;amp; PSR:&lt;/strong&gt; Symfony offers excellent tools and flexibility (&lt;code&gt;psr-http-message-bridge&lt;/code&gt;, Kernel Events) to achieve clean PSR-15 integration via the listener approach. While not PSR-native at its core HTTP layer, its robust component system and extensibility make it a strong choice for developers wanting a full-stack framework that respects and facilitates PSR standard adherence.&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Laravel: Achieving PSR-15 Compliance
&lt;/h3&gt;

&lt;p&gt;Laravel prioritizes developer experience and convention. While it uses HttpFoundation internally and doesn't natively execute PSR-15 handlers, integration is possible.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Option 1: Adapter Pattern (The Basic Approach)&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Concept:&lt;/strong&gt; Similar to Symfony's adapter - create an invokable Laravel controller (&lt;code&gt;__invoke&lt;/code&gt;) that uses the PSR-7 bridge (included via dependencies) to convert the &lt;code&gt;Illuminate\Http\Request&lt;/code&gt;, call the PSR-15 handler, and convert the PSR-7 response back to a Laravel-compatible response. Requires PSR-7 implementation like Nyholm and manual factory setup.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pros:&lt;/strong&gt; Explicit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cons:&lt;/strong&gt; &lt;strong&gt;Significant boilerplate&lt;/strong&gt; per handler. Feels unnatural in the Laravel ecosystem.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Example:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Http\Controllers\Api\Order&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Handler\ProcessOrderHandler&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Http\Request&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Psr\Http\Message\ResponseInterface&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nc"&gt;PsrResponseInterface&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Psr\Http\Message\ServerRequestInterface&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nc"&gt;PsrServerRequestInterface&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// Use appropriate factories - Laravel includes the bridge, but you might need to wire factories&lt;/span&gt;
&lt;span class="c1"&gt;// Usually requires Nyholm PSR-7 implementation `composer require nyholm/psr7`&lt;/span&gt;
&lt;span class="c1"&gt;// and `composer require symfony/psr-http-message-bridge`&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProcessOrderAdapterController&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;ProcessOrderHandler&lt;/span&gt; &lt;span class="nv"&gt;$handler&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;PsrHttpFactory&lt;/span&gt; &lt;span class="nv"&gt;$psrHttpFactory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;HttpFoundationFactory&lt;/span&gt; &lt;span class="nv"&gt;$httpFoundationFactory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ProcessOrderHandler&lt;/span&gt; &lt;span class="nv"&gt;$handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$handler&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Manually create factories or inject them if configured in service container&lt;/span&gt;
        &lt;span class="c1"&gt;// Requires PSR-7 implementation (like Nyholm) to be available&lt;/span&gt;
        &lt;span class="nv"&gt;$psr17Factory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;\Nyholm\Psr7\Factory\Psr17Factory&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;psrHttpFactory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PsrHttpFactory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$psr17Factory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$psr17Factory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$psr17Factory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$psr17Factory&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;httpFoundationFactory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HttpFoundationFactory&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * Handle the incoming request.
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// 1. Convert Laravel Request -&amp;gt; PSR-7 Request&lt;/span&gt;
        &lt;span class="nv"&gt;$psrRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;psrHttpFactory&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;createRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// 2. Call the actual PSR-15 Handler&lt;/span&gt;
        &lt;span class="nv"&gt;$psrResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$psrRequest&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// 3. Convert PSR-7 Response -&amp;gt; Symfony/Laravel Response&lt;/span&gt;
        &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;httpFoundationFactory&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;createResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$psrResponse&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// 4. Return Laravel compatible Response&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Option 2: Centralized Middleware (The Cleaner Approach)&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Concept:&lt;/strong&gt; Create a custom Laravel Middleware. This middleware checks if the controller class resolved by the router for the current route implements &lt;code&gt;RequestHandlerInterface&lt;/code&gt;. If it does, the middleware takes over: it instantiates the handler (via container), performs the Request/Response bridging using PSR-7 factories, executes the handler's &lt;code&gt;handle&lt;/code&gt; method, and returns the converted response directly, bypassing Laravel's standard controller dispatch (&lt;code&gt;$next($request)&lt;/code&gt; is skipped).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Detailed Steps:&lt;/strong&gt;

&lt;ol&gt;
&lt;li&gt; Install PSR-7 implementation: &lt;code&gt;composer require nyholm/psr7&lt;/code&gt;. Ensure bridge is available (usually is).&lt;/li&gt;
&lt;li&gt; Create your PSR-15 handler class.&lt;/li&gt;
&lt;li&gt; Create a Middleware class (e.g., &lt;code&gt;HandlePsr15Requests&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt; Inject or create PSR-7 bridge factories within the middleware.&lt;/li&gt;
&lt;li&gt; In the &lt;code&gt;handle($request, Closure $next)&lt;/code&gt; method:

&lt;ul&gt;
&lt;li&gt;Inspect &lt;code&gt;$request-&amp;gt;route()-&amp;gt;getController()&lt;/code&gt; or &lt;code&gt;$request-&amp;gt;route()-&amp;gt;getActionName()&lt;/code&gt; to find the target handler class.&lt;/li&gt;
&lt;li&gt;Use Reflection or the container to check if it implements &lt;code&gt;RequestHandlerInterface&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If yes: Instantiate handler via &lt;code&gt;app()-&amp;gt;make()&lt;/code&gt;. Convert &lt;code&gt;Illuminate\Http\Request&lt;/code&gt; -&amp;gt; PSR-7 Request. Call &lt;code&gt;handle()&lt;/code&gt;. Convert PSR-7 Response -&amp;gt; Laravel Response. &lt;code&gt;return $laravelResponse;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;If no: &lt;code&gt;return $next($request);&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt; Register the middleware globally or in a specific route group (e.g., &lt;code&gt;api&lt;/code&gt;) in &lt;code&gt;app/Http/Kernel.php&lt;/code&gt;.&lt;/li&gt;

&lt;li&gt; Route directly to the FQCN of your PSR-15 handler class.&lt;/li&gt;

&lt;/ol&gt;

&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Pros:&lt;/strong&gt; &lt;strong&gt;Eliminates adapter boilerplate.&lt;/strong&gt; Centralizes bridging logic. Allows routing directly to PSR-15 handlers.&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Cons:&lt;/strong&gt; Middleware becomes complex and critical. Requires careful handling of route information and potential pipeline order issues. Setting up PSR-7 factories might need a Service Provider. Works slightly "against the grain" of Laravel's typical controller flow.&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Example:&lt;/strong&gt;
&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Closure&lt;/span&gt; &lt;span class="nv"&gt;$next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$route&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nv"&gt;$controllerAction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$route&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getActionName&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Might be 'ClassName' or 'ClassName@method'&lt;/span&gt;

    &lt;span class="nv"&gt;$controllerClass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;is_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$controllerAction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;class_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$controllerAction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="nv"&gt;$controllerAction&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Check if the resolved class exists and implements the interface&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$controllerClass&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;\ReflectionClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$controllerClass&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;implementsInterface&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;\Psr\Http\Server\RequestHandlerInterface&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="c1"&gt;// Instantiate the handler via the container to resolve dependencies&lt;/span&gt;
        &lt;span class="nv"&gt;$psr15Handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;app&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$controllerClass&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Get bridge factories (configure in a Service Provider or create manually)&lt;/span&gt;
        &lt;span class="c1"&gt;// Requires PSR-7 Implementation (e.g., composer require nyholm/psr7)&lt;/span&gt;
        &lt;span class="nv"&gt;$psr17Factory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;\Nyholm\Psr7\Factory\Psr17Factory&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$psrHttpFactory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;\Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$psr17Factory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$psr17Factory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$psr17Factory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$psr17Factory&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$httpFoundationFactory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;\Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Convert Laravel Request -&amp;gt; PSR-7 Request&lt;/span&gt;
        &lt;span class="nv"&gt;$psrRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$psrHttpFactory&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;createRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Execute the PSR-15 Handler&lt;/span&gt;
        &lt;span class="nv"&gt;$psrResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$psr15Handler&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$psrRequest&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Convert PSR-7 Response -&amp;gt; Laravel Response&lt;/span&gt;
        &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$httpFoundationFactory&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;createResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$psrResponse&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Return the response *directly*, bypassing $next() and standard controller dispatch&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// If not a PSR-15 handler route, proceed normally&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Overall Laravel &amp;amp; PSR:&lt;/strong&gt; Laravel &lt;em&gt;can&lt;/em&gt; be made to work with PSR-15 handlers via middleware, significantly cleaning up the adapter approach. However, compared to Symfony's kernel events or Mezzio's native support, it feels less integrated. Laravel's strength lies in its opinionated, rapid development workflow using its native components (Eloquent, Blade, Facades). Pushing for strict PSR-15 handler compliance requires bypassing some of that core flow.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  General Pros and Cons of the Single Action Handler Pattern (Summary)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt; SRP, Testability, Organization, Readability, Precise Dependencies.&lt;br&gt;
&lt;strong&gt;Cons:&lt;/strong&gt; Potentially more files, requires conscious architectural choice.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Use This Pattern
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;API endpoints.&lt;/li&gt;
&lt;li&gt;Single, distinct web actions (form processing, etc.).&lt;/li&gt;
&lt;li&gt;When controller actions become complex.&lt;/li&gt;
&lt;li&gt;To enforce SRP and improve testability.&lt;/li&gt;
&lt;li&gt;As the default in PSR-15 native frameworks.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion &amp;amp; Framework Choice Considerations
&lt;/h2&gt;

&lt;p&gt;The Single Action Handler pattern, especially when implemented using the PSR-15 &lt;code&gt;RequestHandlerInterface&lt;/code&gt;, represents a powerful approach for building modern, maintainable, and testable PHP applications. Adhering to PSR standards like PSR-7 and PSR-15 brings significant benefits in interoperability, reusability, and future-proofing your codebase.&lt;/p&gt;

&lt;p&gt;When choosing a framework with PSR adherence in mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;For Native PSR-15/7 Experience:&lt;/strong&gt; If maximizing interoperability and working directly with PSR standards at the core HTTP layer is your highest priority, a &lt;strong&gt;middleware-centric framework like Mezzio&lt;/strong&gt; is designed specifically for this. It offers the cleanest, most direct path to leveraging PSR-7/15.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;For Full-Stack Power with PSR Flexibility:&lt;/strong&gt; If you require a comprehensive framework with a vast ecosystem, but still want the ability to cleanly integrate and prioritize PSR-15 handlers, &lt;strong&gt;Symfony&lt;/strong&gt; provides excellent flexibility. Its robust DI container, component system, and kernel events (allowing the centralized listener approach) make it a strong contender for building large applications that adhere well to PSR standards with reasonable effort.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;For Rapid Development &amp;amp; DX Prioritizing Framework Conventions:&lt;/strong&gt; If top development speed, an integrated ecosystem, and convention over configuration are paramount, &lt;strong&gt;Laravel&lt;/strong&gt; excels. While achieving strict PSR-15 handler compliance requires more deliberate effort (via the centralized middleware approach, working slightly against the native flow), it's possible. However, the main draw of Laravel often lies in embracing &lt;em&gt;its&lt;/em&gt; way of doing things.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>php</category>
      <category>psr</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
