@@ -756,4 +756,115 @@ public function testCallableStringParametersNotExecuted(): void
756756
757757 $ this ->assertSame ('generated: generated-value ' , $ result );
758758 }
759+
760+ public function testContainerIsolationBetweenRequests (): void
761+ {
762+ $ this ->http
763+ ->error ()
764+ ->inject ('error ' )
765+ ->inject ('response ' )
766+ ->action (function ($ error , $ response ) {
767+ $ response ->send ('error: ' . $ error ->getMessage ());
768+ });
769+
770+ // Route that echoes request-scoped value
771+ $ route = $ this ->http ->addRoute ('GET ' , '/isolation-test ' );
772+ $ route
773+ ->inject ('request ' )
774+ ->action (function ($ request ) {
775+ echo $ request ->getHeader ('x-req-id ' , 'none ' );
776+ });
777+
778+ // First request
779+ $ container1 = new Container ($ this ->context );
780+ $ container1 ->set ('request ' , function () {
781+ $ request = new Request ([]);
782+ $ request ->setURI ('/isolation-test ' );
783+ $ request ->setMethod ('GET ' );
784+ $ request ->addHeader ('x-req-id ' , 'first ' );
785+ return $ request ;
786+ });
787+ $ container1 ->set ('response ' , fn () => new Response ());
788+
789+ \ob_start ();
790+ $ this ->http ->run ($ container1 );
791+ $ result1 = \ob_get_contents ();
792+ \ob_end_clean ();
793+
794+ // Second request with different header
795+ $ container2 = new Container ($ this ->context );
796+ $ container2 ->set ('request ' , function () {
797+ $ request = new Request ([]);
798+ $ request ->setURI ('/isolation-test ' );
799+ $ request ->setMethod ('GET ' );
800+ $ request ->addHeader ('x-req-id ' , 'second ' );
801+ return $ request ;
802+ });
803+ $ container2 ->set ('response ' , fn () => new Response ());
804+
805+ \ob_start ();
806+ $ this ->http ->run ($ container2 );
807+ $ result2 = \ob_get_contents ();
808+ \ob_end_clean ();
809+
810+ // Each child container should resolve its own request, not bleed across
811+ $ this ->assertSame ('first ' , $ result1 );
812+ $ this ->assertSame ('second ' , $ result2 , 'Second request must not see first request state ' );
813+
814+ // Parent container must not be polluted with request-scoped deps
815+ $ this ->assertFalse ($ this ->context ->has ('route ' ));
816+ }
817+
818+ public function testContainerIsolationForErrors (): void
819+ {
820+ $ errorMessages = [];
821+
822+ $ this ->http
823+ ->error ()
824+ ->inject ('error ' )
825+ ->action (function ($ error ) use (&$ errorMessages ) {
826+ $ errorMessages [] = $ error ->getMessage ();
827+ });
828+
829+ // Route that always throws
830+ $ route = $ this ->http ->addRoute ('GET ' , '/error-isolation ' );
831+ $ route
832+ ->param ('msg ' , '' , new Text (200 ), 'error message ' )
833+ ->action (function ($ msg ) {
834+ throw new Exception ($ msg , 500 );
835+ });
836+
837+ // First request triggers error "first"
838+ $ container1 = new Container ($ this ->context );
839+ $ container1 ->set ('request ' , function () {
840+ $ request = new Request (['msg ' => 'first ' ]);
841+ $ request ->setURI ('/error-isolation ' );
842+ $ request ->setMethod ('GET ' );
843+ return $ request ;
844+ });
845+ $ container1 ->set ('response ' , fn () => new Response ());
846+
847+ \ob_start ();
848+ $ this ->http ->run ($ container1 );
849+ \ob_end_clean ();
850+
851+ // Second request triggers error "second"
852+ $ container2 = new Container ($ this ->context );
853+ $ container2 ->set ('request ' , function () {
854+ $ request = new Request (['msg ' => 'second ' ]);
855+ $ request ->setURI ('/error-isolation ' );
856+ $ request ->setMethod ('GET ' );
857+ return $ request ;
858+ });
859+ $ container2 ->set ('response ' , fn () => new Response ());
860+
861+ \ob_start ();
862+ $ this ->http ->run ($ container2 );
863+ \ob_end_clean ();
864+
865+ // Each error handler should receive its own error, not a stale one
866+ $ this ->assertCount (2 , $ errorMessages );
867+ $ this ->assertSame ('first ' , $ errorMessages [0 ]);
868+ $ this ->assertSame ('second ' , $ errorMessages [1 ], 'Second error handler should not receive stale error from first request ' );
869+ }
759870}
0 commit comments