diff --git a/src/Support/ReflectionClosure.php b/src/Support/ReflectionClosure.php index c563c1ca..d2a70105 100644 --- a/src/Support/ReflectionClosure.php +++ b/src/Support/ReflectionClosure.php @@ -511,8 +511,7 @@ public function getCode() // named arguments... case ':': if ($lastState === 'closure' && $context === 'root') { - $state = 'ignore_next'; - $lastState = 'closure'; + $state = 'closure'; $code .= $id_start.$token; } diff --git a/tests/Fixtures/RegularClass.php b/tests/Fixtures/RegularClass.php new file mode 100644 index 00000000..96ca0995 --- /dev/null +++ b/tests/Fixtures/RegularClass.php @@ -0,0 +1,42 @@ +toBeCode($e1); +}); + +test('consts', function () { + $f1 = function () { + return RegularClass::C; + }; + + $e1 = 'function () { + return \Tests\Fixtures\RegularClass::C; + }'; + + expect($f1)->toBeCode($e1); }); diff --git a/tests/ReflectionClosure6Test.php b/tests/ReflectionClosure6Test.php new file mode 100644 index 00000000..e69de29b diff --git a/tests/ReflectionClosurePhp81Test.php b/tests/ReflectionClosurePhp81Test.php index 9cbafec0..cbe50c82 100644 --- a/tests/ReflectionClosurePhp81Test.php +++ b/tests/ReflectionClosurePhp81Test.php @@ -3,6 +3,7 @@ use Foo\Baz\Qux\Forest; use Some\ClassName as ClassAlias; use Tests\Fixtures\Model; +use Tests\Fixtures\RegularClass; use function Tests\Fixtures\{makeModel}; enum GlobalEnum { @@ -11,6 +12,276 @@ enum GlobalEnum { case Moderator; } +test('named arguments', function () { + $variable = new RegularClass(); + + $f1 = function (string $a1) use ($variable) { + return new RegularClass( + a1: $a1, + a2: 'string', + a3: 1, + a4: 1.1, + a5: true, + a6: null, + a7: ['string'], + a8: ['string', $a1, 1, null, true], + a9: [[[[['string', $a1, 1, null, true]]]]], + a10: new RegularClass( + a1: $a1, + a2: 'string', + a3: 1, + a4: 1.1, + a5: true, + a6: null, + a7: ['string'], + a8: ['string', $a1, 1, null, true], + a9: [[[[['string', $a1, 1, null, true]]]]], + a10: new RegularClass(), + a11: RegularClass::C, + a12: RegularClass::staticMethod(), + a13: (new RegularClass())->instanceMethod(), + a14: [new RegularClass(), RegularClass::C, RegularClass::staticMethod(), (new RegularClass())->instanceMethod()], + ), + a11: RegularClass::C, + a12: [new RegularClass(), RegularClass::C], + a13: RegularClass::staticMethod(), + a14: (new RegularClass())->instanceMethod(), + a15: fn () => new RegularClass( + a1: $a1, + a2: 'string', + a3: 1, + a4: 1.1, + a5: true, + a6: null, + a7: ['string'], + a8: ['string', $a1, 1, null, true], + a9: [[[[['string', $a1, 1, null, true]]]]], + a10: new RegularClass( + a1: $a1, + a2: 'string', + a3: 1, + a4: 1.1, + a5: true, + a6: null, + a7: ['string'], + a8: ['string', $a1, 1, null, true], + a9: [[[[['string', $a1, 1, null, true]]]]], + a10: new RegularClass(), + a11: RegularClass::C, + a12: RegularClass::staticMethod(), + a13: (new RegularClass())->instanceMethod(), + a14: [new RegularClass(), RegularClass::C, RegularClass::staticMethod(), (new RegularClass())->instanceMethod()], + ), + a11: RegularClass::C, + a12: [new RegularClass(), RegularClass::C], + a13: RegularClass::staticMethod(), + a14: (new RegularClass())->instanceMethod(), + ), + a16: fn () => fn () => new RegularClass( + a1: $a1, + a2: 'string', + a3: 1, + a4: 1.1, + a5: true, + a6: null, + a7: ['string'], + a8: ['string', $a1, 1, null, true], + a9: [[[[['string', $a1, 1, null, true]]]]], + a10: new RegularClass( + a1: $a1, + a2: 'string', + a3: 1, + a4: 1.1, + a5: true, + a6: null, + a7: ['string'], + a8: ['string', $a1, 1, null, true], + a9: [[[[['string', $a1, 1, null, true]]]]], + a10: new RegularClass(), + a11: RegularClass::C, + a12: RegularClass::staticMethod(), + a13: (new RegularClass())->instanceMethod(), + a14: [new RegularClass(), RegularClass::C, RegularClass::staticMethod(), (new RegularClass())->instanceMethod()], + ), + a11: RegularClass::C, + a12: [new RegularClass(), RegularClass::C], + a13: RegularClass::staticMethod(), + a14: (new RegularClass())->instanceMethod(), + ), + a17: function () use ($variable) { + return new RegularClass( + a1: $a1, + a2: 'string', + a3: 1, + a4: 1.1, + a5: true, + a6: null, + a7: ['string'], + a8: ['string', $a1, 1, null, true], + a9: [[[[['string', $a1, 1, null, true]]]]], + a10: new RegularClass( + a1: $a1, + a2: 'string', + a3: 1, + a4: 1.1, + a5: true, + a6: null, + a7: ['string'], + a8: ['string', $a1, 1, null, true], + a9: [[[[['string', $a1, 1, null, true]]]]], + a10: new RegularClass(), + a11: RegularClass::C, + a12: RegularClass::staticMethod(), + a13: (new RegularClass())->instanceMethod(), + a14: [new RegularClass(), RegularClass::C, RegularClass::staticMethod(), (new RegularClass())->instanceMethod()], + ), + a11: RegularClass::C, + a12: [new RegularClass(), RegularClass::C], + a13: RegularClass::staticMethod(), + a14: (new RegularClass())->instanceMethod(), + ); + }, + a18: reflection_closure_my_function(), + a19: reflection_closure_my_function(ReflectionClosureGlobalEnum::Guest), + a20: reflection_closure_my_function(enum: ReflectionClosureGlobalEnum::Guest), + ); + }; + + $e1 = "function (string \$a1) use (\$variable) { + return new \Tests\Fixtures\RegularClass( + a1: \$a1, + a2: 'string', + a3: 1, + a4: 1.1, + a5: true, + a6: null, + a7: ['string'], + a8: ['string', \$a1, 1, null, true], + a9: [[[[['string', \$a1, 1, null, true]]]]], + a10: new \Tests\Fixtures\RegularClass( + a1: \$a1, + a2: 'string', + a3: 1, + a4: 1.1, + a5: true, + a6: null, + a7: ['string'], + a8: ['string', \$a1, 1, null, true], + a9: [[[[['string', \$a1, 1, null, true]]]]], + a10: new \Tests\Fixtures\RegularClass(), + a11: \Tests\Fixtures\RegularClass::C, + a12: \Tests\Fixtures\RegularClass::staticMethod(), + a13: (new \Tests\Fixtures\RegularClass())->instanceMethod(), + a14: [new \Tests\Fixtures\RegularClass(), \Tests\Fixtures\RegularClass::C, \Tests\Fixtures\RegularClass::staticMethod(), (new \Tests\Fixtures\RegularClass())->instanceMethod()], + ), + a11: \Tests\Fixtures\RegularClass::C, + a12: [new \Tests\Fixtures\RegularClass(), \Tests\Fixtures\RegularClass::C], + a13: \Tests\Fixtures\RegularClass::staticMethod(), + a14: (new \Tests\Fixtures\RegularClass())->instanceMethod(), + a15: fn () => new \Tests\Fixtures\RegularClass( + a1: \$a1, + a2: 'string', + a3: 1, + a4: 1.1, + a5: true, + a6: null, + a7: ['string'], + a8: ['string', \$a1, 1, null, true], + a9: [[[[['string', \$a1, 1, null, true]]]]], + a10: new \Tests\Fixtures\RegularClass( + a1: \$a1, + a2: 'string', + a3: 1, + a4: 1.1, + a5: true, + a6: null, + a7: ['string'], + a8: ['string', \$a1, 1, null, true], + a9: [[[[['string', \$a1, 1, null, true]]]]], + a10: new \Tests\Fixtures\RegularClass(), + a11: \Tests\Fixtures\RegularClass::C, + a12: \Tests\Fixtures\RegularClass::staticMethod(), + a13: (new \Tests\Fixtures\RegularClass())->instanceMethod(), + a14: [new \Tests\Fixtures\RegularClass(), \Tests\Fixtures\RegularClass::C, \Tests\Fixtures\RegularClass::staticMethod(), (new \Tests\Fixtures\RegularClass())->instanceMethod()], + ), + a11: \Tests\Fixtures\RegularClass::C, + a12: [new \Tests\Fixtures\RegularClass(), \Tests\Fixtures\RegularClass::C], + a13: \Tests\Fixtures\RegularClass::staticMethod(), + a14: (new \Tests\Fixtures\RegularClass())->instanceMethod(), + ), + a16: fn () => fn () => new \Tests\Fixtures\RegularClass( + a1: \$a1, + a2: 'string', + a3: 1, + a4: 1.1, + a5: true, + a6: null, + a7: ['string'], + a8: ['string', \$a1, 1, null, true], + a9: [[[[['string', \$a1, 1, null, true]]]]], + a10: new \Tests\Fixtures\RegularClass( + a1: \$a1, + a2: 'string', + a3: 1, + a4: 1.1, + a5: true, + a6: null, + a7: ['string'], + a8: ['string', \$a1, 1, null, true], + a9: [[[[['string', \$a1, 1, null, true]]]]], + a10: new \Tests\Fixtures\RegularClass(), + a11: \Tests\Fixtures\RegularClass::C, + a12: \Tests\Fixtures\RegularClass::staticMethod(), + a13: (new \Tests\Fixtures\RegularClass())->instanceMethod(), + a14: [new \Tests\Fixtures\RegularClass(), \Tests\Fixtures\RegularClass::C, \Tests\Fixtures\RegularClass::staticMethod(), (new \Tests\Fixtures\RegularClass())->instanceMethod()], + ), + a11: \Tests\Fixtures\RegularClass::C, + a12: [new \Tests\Fixtures\RegularClass(), \Tests\Fixtures\RegularClass::C], + a13: \Tests\Fixtures\RegularClass::staticMethod(), + a14: (new \Tests\Fixtures\RegularClass())->instanceMethod(), + ), + a17: function () use (\$variable) { + return new \Tests\Fixtures\RegularClass( + a1: \$a1, + a2: 'string', + a3: 1, + a4: 1.1, + a5: true, + a6: null, + a7: ['string'], + a8: ['string', \$a1, 1, null, true], + a9: [[[[['string', \$a1, 1, null, true]]]]], + a10: new \Tests\Fixtures\RegularClass( + a1: \$a1, + a2: 'string', + a3: 1, + a4: 1.1, + a5: true, + a6: null, + a7: ['string'], + a8: ['string', \$a1, 1, null, true], + a9: [[[[['string', \$a1, 1, null, true]]]]], + a10: new \Tests\Fixtures\RegularClass(), + a11: \Tests\Fixtures\RegularClass::C, + a12: \Tests\Fixtures\RegularClass::staticMethod(), + a13: (new \Tests\Fixtures\RegularClass())->instanceMethod(), + a14: [new \Tests\Fixtures\RegularClass(), \Tests\Fixtures\RegularClass::C, \Tests\Fixtures\RegularClass::staticMethod(), (new \Tests\Fixtures\RegularClass())->instanceMethod()], + ), + a11: \Tests\Fixtures\RegularClass::C, + a12: [new \Tests\Fixtures\RegularClass(), \Tests\Fixtures\RegularClass::C], + a13: \Tests\Fixtures\RegularClass::staticMethod(), + a14: (new \Tests\Fixtures\RegularClass())->instanceMethod(), + ); + }, + a18: \\reflection_closure_my_function(), + a19: \\reflection_closure_my_function(\ReflectionClosureGlobalEnum::Guest), + a20: \\reflection_closure_my_function(enum: \ReflectionClosureGlobalEnum::Guest), + ); + }"; + + expect($f1)->toBeCode($e1); +})->with('serializers'); + test('enums', function () { $f = function (GlobalEnum $role) { return $role; @@ -419,3 +690,14 @@ public function getSelf(self $instance): self return $instance; } } + +enum ReflectionClosureGlobalEnum { + case Admin; + case Guest; + case Moderator; +} + +function reflection_closure_my_function(SerializerGlobalEnum $enum = SerializerGlobalEnum::Admin) +{ + return $enum; +} diff --git a/tests/SerializerPhp80Test.php b/tests/SerializerPhp80Test.php index 2368565d..cc16d3ec 100644 --- a/tests/SerializerPhp80Test.php +++ b/tests/SerializerPhp80Test.php @@ -1,5 +1,7 @@ toBe(s($f1)()); })->with('serializers'); +test('named arguments with namespaced class const parameter', function () { + $f1 = function () { + return new RegularClass(a2: RegularClass::C); + }; + + $instance = s($f1)(); + + expect($instance)->toBeInstanceOf(RegularClass::class) + ->and($instance->a1)->toBeNull() + ->and($instance->a2)->toBe('CONST'); +})->with('serializers'); + +test('named arguments with namespaced class instance parameter', function () { + $f1 = function () { + return new RegularClass(a2: new RegularClass()); + }; + + $instance = s($f1)(); + + expect($instance)->toBeInstanceOf(RegularClass::class) + ->and($instance->a1)->toBeNull() + ->and($instance->a2)->toBeInstanceOf(RegularClass::class); +})->with('serializers'); + class SerializerPhp80NamedArguments { public function publicMethod(string $namedArgument, $namedArgumentB = null) diff --git a/tests/SerializerPhp81Test.php b/tests/SerializerPhp81Test.php index 4e99069f..3add007c 100644 --- a/tests/SerializerPhp81Test.php +++ b/tests/SerializerPhp81Test.php @@ -2,6 +2,7 @@ use Tests\Fixtures\Model; use Tests\Fixtures\ModelAttribute; +use Tests\Fixtures\RegularClass; test('enums', function () { $f = function (SerializerGlobalEnum $role) { @@ -355,6 +356,167 @@ enum SerializerScopedBackedEnum: string { expect($f())->toBeFalse(); })->with('serializers'); +test('named arguments', function () { + $variable = 'variableValue'; + + $f = function (string $a1) use ($variable) { + return new RegularClass( + a1: $a1, + a2: 'string', + a3: 1, + a4: 1.1, + a5: true, + a6: null, + a7: ['string'], + a8: ['string', $a1, 1, null, true], + a9: [[[[['string', $a1, 1, null, true]]]]], + a10: new RegularClass( + a1: $a1, + a2: 'string', + a3: 1, + a4: 1.1, + a5: true, + a6: null, + a7: ['string'], + a8: ['string', $a1, 1, null, true], + a9: [[[[['string', $a1, 1, null, true]]]]], + a10: new RegularClass(), + a11: RegularClass::C, + a12: RegularClass::staticMethod(), + a13: (new RegularClass())->instanceMethod(), + a14: [new RegularClass(), RegularClass::C, RegularClass::staticMethod(), (new RegularClass())->instanceMethod()], + ), + a11: RegularClass::C, + a12: [new RegularClass(), RegularClass::C], + a13: RegularClass::staticMethod(), + a14: (new RegularClass())->instanceMethod(), + a15: fn () => new RegularClass( + a1: $a1, + a2: 'string', + a3: 1, + a4: 1.1, + a5: true, + a6: null, + a7: ['string'], + a8: ['string', $a1, 1, null, true], + a9: [[[[['string', $a1, 1, null, true]]]]], + a10: new RegularClass( + a1: $a1, + a2: 'string', + a3: 1, + a4: 1.1, + a5: true, + a6: null, + a7: ['string'], + a8: ['string', $a1, 1, null, true], + a9: [[[[['string', $a1, 1, null, true]]]]], + a10: new RegularClass(), + a11: RegularClass::C, + a12: RegularClass::staticMethod(), + a13: (new RegularClass())->instanceMethod(), + a14: [new RegularClass(), RegularClass::C, RegularClass::staticMethod(), (new RegularClass())->instanceMethod()], + ), + a11: RegularClass::C, + a12: [new RegularClass(), RegularClass::C], + a13: RegularClass::staticMethod(), + a14: (new RegularClass())->instanceMethod(), + ), + a16: fn () => fn () => new RegularClass( + a1: $a1, + a2: 'string', + a3: 1, + a4: 1.1, + a5: true, + a6: null, + a7: ['string'], + a8: ['string', $a1, 1, null, true], + a9: [[[[['string', $a1, 1, null, true]]]]], + a10: new RegularClass( + a1: $a1, + a2: 'string', + a3: 1, + a4: 1.1, + a5: true, + a6: null, + a7: ['string'], + a8: ['string', $a1, 1, null, true], + a9: [[[[['string', $a1, 1, null, true]]]]], + a10: new RegularClass(), + a11: RegularClass::C, + a12: RegularClass::staticMethod(), + a13: (new RegularClass())->instanceMethod(), + a14: [new RegularClass(), RegularClass::C, RegularClass::staticMethod(), (new RegularClass())->instanceMethod()], + ), + a11: RegularClass::C, + a12: [new RegularClass(), RegularClass::C], + a13: RegularClass::staticMethod(), + a14: (new RegularClass())->instanceMethod(), + ), + a17: function () use ($variable) { + return new RegularClass( + a1: $a1, + a2: 'string', + a3: 1, + a4: 1.1, + a5: true, + a6: null, + a7: ['string'], + a8: ['string', $a1, 1, null, true], + a9: [[[[['string', $a1, 1, null, true]]]]], + a10: new RegularClass( + a1: $a1, + a2: 'string', + a3: 1, + a4: 1.1, + a5: true, + a6: null, + a7: ['string'], + a8: ['string', $a1, 1, null, true], + a9: [[[[['string', $a1, 1, null, true]]]]], + a10: new RegularClass(), + a11: RegularClass::C, + a12: RegularClass::staticMethod(), + a13: (new RegularClass())->instanceMethod(), + a14: [new RegularClass(), RegularClass::C, RegularClass::staticMethod(), (new RegularClass())->instanceMethod()], + ), + a11: RegularClass::C, + a12: [new RegularClass(), RegularClass::C], + a13: RegularClass::staticMethod(), + a14: (new RegularClass())->instanceMethod(), + ); + }, + a18: serializer_my_function(), + a19: serializer_my_function(SerializerGlobalEnum::Guest), + a20: serializer_my_function(enum: SerializerGlobalEnum::Guest), + ); + }; + + $f = s($f); + + $instance = $f('a1'); + + $expectedArray = [ + 'a1' => 'a1', + 'a2' => 'string', + 'a3' => 1, + 'a4' => 1.1, + 'a5' => true, + 'a6' => null, + 'a7' => ['string'], + 'a8' => ['string', 'a1', 1, null, true], + 'a9' => [[[[['string', 'a1', 1, null, true]]]]], + ]; + + expect($instance) + ->toMatchArray($expectedArray) + ->toMatchArray([ + 'a18' => SerializerGlobalEnum::Admin, + 'a19' => SerializerGlobalEnum::Guest, + 'a20' => SerializerGlobalEnum::Guest, + ]) + ->and($instance->a15->__invoke())->toMatchArray($expectedArray); +})->with('serializers'); + test('function attributes with named arguments', function () { $model = new Model(); @@ -511,6 +673,14 @@ public function getClosure() } } +test('named arguments with namespaced enum parameter', function () { + $f1 = function () { + return new RegularClass(a2: RegularClass::C); + }; + + expect(s($f1)())->toBeInstanceOf(RegularClass::class); +})->with('serializers'); + class ClassWithBackedEnumProperty { public SerializerGlobalBackedEnum $enum = SerializerGlobalBackedEnum::Admin; @@ -522,3 +692,8 @@ public function getClosure() }; } } + +function serializer_my_function(SerializerGlobalEnum $enum = SerializerGlobalEnum::Admin) +{ + return $enum; +} diff --git a/tests/SerializerTest.php b/tests/SerializerTest.php index 56ec800a..a5169a97 100644 --- a/tests/SerializerTest.php +++ b/tests/SerializerTest.php @@ -8,6 +8,16 @@ use Laravel\SerializableClosure\UnsignedSerializableClosure; use Tests\Fixtures\Model; +test('closure with simple const', function () { + $c = function () { + return ObjWithConst::FOO; + }; + + $u = s($c)(); + + expect($u)->toBe('bar'); +})->with('serializers'); + test('closure use return value', function () { $a = 100; $c = function () use ($a) { @@ -552,3 +562,8 @@ class ObjSelf { public $o; } + +class ObjWithConst +{ + const FOO = 'bar'; +}