File tree Expand file tree Collapse file tree 6 files changed +124
-1
lines changed Expand file tree Collapse file tree 6 files changed +124
-1
lines changed Original file line number Diff line number Diff line change @@ -96,7 +96,7 @@ public function getCode()
9696 $ builtin_types = self ::getBuiltinTypes ();
9797 $ class_keywords = ['self ' , 'static ' , 'parent ' ];
9898
99- $ ns = $ this ->getNamespaceName ();
99+ $ ns = $ this ->getClosureNamespaceName ();
100100 $ nsf = $ ns == '' ? '' : ($ ns [0 ] == '\\' ? $ ns : '\\' .$ ns );
101101
102102 $ _file = var_export ($ fileName , true );
@@ -1133,6 +1133,23 @@ protected function fetchItems()
11331133 static ::$ structures [$ key ] = $ structures ;
11341134 }
11351135
1136+ /**
1137+ * Returns the namespace associated to the closure.
1138+ *
1139+ * @return string
1140+ */
1141+ protected function getClosureNamespaceName ()
1142+ {
1143+ $ ns = $ this ->getNamespaceName ();
1144+
1145+ // First class callables...
1146+ if ($ this ->getName () !== '{closure} ' && empty ($ ns ) && ! is_null ($ this ->getClosureScopeClass ())) {
1147+ $ ns = $ this ->getClosureScopeClass ()->getNamespaceName ();
1148+ }
1149+
1150+ return $ ns ;
1151+ }
1152+
11361153 /**
11371154 * Parse the given token.
11381155 *
Original file line number Diff line number Diff line change 1+ <?php
2+
3+ namespace Tests \Fixtures ;
4+
5+ class Model
6+ {
7+ public function make (Model $ model ): Model
8+ {
9+ return new Model ();
10+ }
11+
12+ public static function staticMake (Model $ model ): Model
13+ {
14+ return new Model ();
15+ }
16+ }
Original file line number Diff line number Diff line change 44use Foo \Baz \Qux ;
55use Foo \Baz \Qux \Forest ;
66use Laravel \SerializableClosure \Support \ReflectionClosure ;
7+ use Tests \Fixtures \Model ;
78
89test ('is short closure ' , function () {
910 $ f1 = fn () => 1 ;
152153 expect ($ f )->toBeCode ($ e );
153154});
154155
156+ test ('from callable namespaces ' , function () {
157+ $ f = Closure::fromCallable ([new Model , 'make ' ]);
158+
159+ $ e = 'function (\Tests\Fixtures\Model $model): \Tests\Fixtures\Model
160+ {
161+ return new \Tests\Fixtures\Model();
162+ } ' ;
163+
164+ expect ($ f )->toBeCode ($ e );
165+ });
166+
167+ test ('from static callable namespaces ' , function () {
168+ $ f = Closure::fromCallable ([Model::class, 'staticMake ' ]);
169+
170+ $ e = 'static function (\Tests\Fixtures\Model $model): \Tests\Fixtures\Model
171+ {
172+ return new \Tests\Fixtures\Model();
173+ } ' ;
174+
175+ expect ($ f )->toBeCode ($ e );
176+ });
177+
155178// Helpers
156179function c (Closure $ closure )
157180{
Original file line number Diff line number Diff line change 22
33use Foo \Baz \Qux \Forest ;
44use Some \ClassName as ClassAlias ;
5+ use Tests \Fixtures \Model ;
6+ use function Tests \Fixtures \{makeModel };
57
68enum GlobalEnum {
79 case Admin;
@@ -256,6 +258,32 @@ enum ScopedBackedEnum: string {
256258 expect ($ f )->toBeCode ($ e );
257259})->skip ('Constants in anonymous classes is not supported. ' );
258260
261+ test ('first-class callable namespaces ' , function () {
262+ $ model = new Model ();
263+
264+ $ f = $ model ->make (...);
265+
266+ $ e = 'function (\Tests\Fixtures\Model $model): \Tests\Fixtures\Model
267+ {
268+ return new \Tests\Fixtures\Model();
269+ } ' ;
270+
271+ expect ($ f )->toBeCode ($ e );
272+ });
273+
274+ test ('static first-class callable namespaces ' , function () {
275+ $ model = new Model ();
276+
277+ $ f = $ model ->staticMake (...);
278+
279+ $ e = 'static function (\Tests\Fixtures\Model $model): \Tests\Fixtures\Model
280+ {
281+ return new \Tests\Fixtures\Model();
282+ } ' ;
283+
284+ expect ($ f )->toBeCode ($ e );
285+ });
286+
259287class ReflectionClosurePhp81Service
260288{
261289}
Original file line number Diff line number Diff line change 11<?php
22
3+ use Tests \Fixtures \Model ;
4+
35enum SerializerGlobalEnum {
46 case Admin;
57 case Guest;
@@ -280,6 +282,26 @@ enum SerializerScopedBackedEnum: string {
280282 expect ($ object ->getPrivate ())->toBe ('private ' );
281283})->with ('serializers ' );
282284
285+ test ('first-class callable namespaces ' , function () {
286+ $ model = new Model ();
287+
288+ $ f = $ model ->make (...);
289+
290+ $ f = s ($ f );
291+
292+ expect ($ f (new Model ))->toBeInstanceOf (Model::class);
293+ })->with ('serializers ' );
294+
295+ test ('static first-class callable namespaces ' , function () {
296+ $ model = new Model ();
297+
298+ $ f = $ model ->staticMake (...);
299+
300+ $ f = s ($ f );
301+
302+ expect ($ f (new Model ))->toBeInstanceOf (Model::class);
303+ })->with ('serializers ' );
304+
283305interface SerializerPhp81HasId {}
284306interface SerializerPhp81HasName {}
285307
Original file line number Diff line number Diff line change 33use Laravel \SerializableClosure \SerializableClosure ;
44use Laravel \SerializableClosure \Serializers \Signed ;
55use Laravel \SerializableClosure \Support \ReflectionClosure ;
6+ use Tests \Fixtures \Model ;
67
78test ('closure use return value ' , function () {
89 $ a = 100 ;
@@ -384,6 +385,22 @@ function () {
384385 expect ($ r )->toEqual ('Hi ' );
385386})->with ('serializers ' );
386387
388+ test ('from callable namespaces ' , function () {
389+ $ f = Closure::fromCallable ([new Model , 'make ' ]);
390+
391+ $ f = s ($ f );
392+
393+ expect ($ f (new Model ))->toBeInstanceOf (Model::class);
394+ })->with ('serializers ' );
395+
396+ test ('from static callable namespaces ' , function () {
397+ $ f = Closure::fromCallable ([new Model , 'staticMake ' ]);
398+
399+ $ f = s ($ f );
400+
401+ expect ($ f (new Model ))->toBeInstanceOf (Model::class);
402+ })->with ('serializers ' );
403+
387404class A
388405{
389406 protected static function aStaticProtected ()
You can’t perform that action at this time.
0 commit comments