From ff62eb76793e219320a54d63f9d0c6ce18ef3835 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Faugeron?= Date: Fri, 6 Feb 2026 07:17:24 +0000 Subject: [PATCH 01/18] chore: added PHP 7.0 CS Fixer rules --- .php-cs-fixer.dist.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 3aa6af7..2f9f5c8 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -35,6 +35,8 @@ return (new PhpCsFixer\Config()) ->setRules([ '@Symfony' => true, + '@PHP70Migration' => true, + '@PHP70Migration:risky' => true, // [Symfony] defaults to `camelCase`, we set it to `snake_case` (phpspec style) 'php_unit_method_casing' => ['case' => 'snake_case'], @@ -42,6 +44,7 @@ // [Symfony] defaults to `true`, we set it to `false` for phpspec 'visibility_required' => false, ]) + ->setRiskyAllowed(true) ->setUsingCache(true) ->setFinder($finder) ; From dcbc86b818cfc30867727f5deb6b028d3e4e9582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Faugeron?= Date: Fri, 6 Feb 2026 07:17:57 +0000 Subject: [PATCH 02/18] chore: Fixed CS --- spec/Memio/Model/ArgumentSpec.php | 2 ++ spec/Memio/Model/ConstantSpec.php | 2 ++ spec/Memio/Model/ContractSpec.php | 2 ++ spec/Memio/Model/FileSpec.php | 2 ++ spec/Memio/Model/FullyQualifiedNameSpec.php | 2 ++ spec/Memio/Model/MethodSpec.php | 2 ++ spec/Memio/Model/ObjektSpec.php | 2 ++ spec/Memio/Model/Phpdoc/ApiTagSpec.php | 2 ++ spec/Memio/Model/Phpdoc/DeprecationTagSpec.php | 2 ++ spec/Memio/Model/Phpdoc/DescriptionSpec.php | 2 ++ spec/Memio/Model/Phpdoc/LicensePhpdocSpec.php | 2 ++ spec/Memio/Model/Phpdoc/MethodPhpdocSpec.php | 2 ++ spec/Memio/Model/Phpdoc/ParameterTagSpec.php | 2 ++ spec/Memio/Model/Phpdoc/PropertyPhpdocSpec.php | 2 ++ spec/Memio/Model/Phpdoc/StructurePhpdocSpec.php | 2 ++ spec/Memio/Model/Phpdoc/VariableTagSpec.php | 2 ++ spec/Memio/Model/PropertySpec.php | 2 ++ spec/Memio/Model/TypeSpec.php | 2 ++ src/Memio/Model/Argument.php | 2 ++ src/Memio/Model/Constant.php | 2 ++ src/Memio/Model/Contract.php | 2 ++ src/Memio/Model/File.php | 2 ++ src/Memio/Model/FullyQualifiedName.php | 2 ++ src/Memio/Model/Method.php | 2 ++ src/Memio/Model/Objekt.php | 2 ++ src/Memio/Model/Phpdoc/ApiTag.php | 2 ++ src/Memio/Model/Phpdoc/DeprecationTag.php | 2 ++ src/Memio/Model/Phpdoc/Description.php | 2 ++ src/Memio/Model/Phpdoc/LicensePhpdoc.php | 2 ++ src/Memio/Model/Phpdoc/MethodPhpdoc.php | 2 ++ src/Memio/Model/Phpdoc/ParameterTag.php | 2 ++ src/Memio/Model/Phpdoc/PropertyPhpdoc.php | 2 ++ src/Memio/Model/Phpdoc/ReturnTag.php | 2 ++ src/Memio/Model/Phpdoc/StructurePhpdoc.php | 2 ++ src/Memio/Model/Phpdoc/ThrowTag.php | 2 ++ src/Memio/Model/Phpdoc/VariableTag.php | 2 ++ src/Memio/Model/Property.php | 2 ++ src/Memio/Model/Structure.php | 2 ++ src/Memio/Model/Type.php | 2 ++ 39 files changed, 78 insertions(+) diff --git a/spec/Memio/Model/ArgumentSpec.php b/spec/Memio/Model/ArgumentSpec.php index 918e545..0e1971b 100644 --- a/spec/Memio/Model/ArgumentSpec.php +++ b/spec/Memio/Model/ArgumentSpec.php @@ -1,5 +1,7 @@ Date: Fri, 6 Feb 2026 07:18:30 +0000 Subject: [PATCH 03/18] chore: added PHP 7.1 CS Fixer rules --- .php-cs-fixer.dist.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 2f9f5c8..e0e4ff8 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -35,8 +35,8 @@ return (new PhpCsFixer\Config()) ->setRules([ '@Symfony' => true, - '@PHP70Migration' => true, - '@PHP70Migration:risky' => true, + '@PHP71Migration' => true, + '@PHP71Migration:risky' => true, // [Symfony] defaults to `camelCase`, we set it to `snake_case` (phpspec style) 'php_unit_method_casing' => ['case' => 'snake_case'], From 0b6346bba512f0760f03aba74b22b2cf61d607d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Faugeron?= Date: Fri, 6 Feb 2026 07:19:00 +0000 Subject: [PATCH 04/18] chore: Fixed CS --- spec/Memio/Model/ArgumentSpec.php | 10 ++-- spec/Memio/Model/ConstantSpec.php | 6 +-- spec/Memio/Model/ContractSpec.php | 18 +++---- spec/Memio/Model/FileSpec.php | 12 ++--- spec/Memio/Model/FullyQualifiedNameSpec.php | 12 ++--- spec/Memio/Model/MethodSpec.php | 20 ++++---- spec/Memio/Model/ObjektSpec.php | 26 +++++----- spec/Memio/Model/Phpdoc/ApiTagSpec.php | 2 +- .../Memio/Model/Phpdoc/DeprecationTagSpec.php | 6 +-- spec/Memio/Model/Phpdoc/DescriptionSpec.php | 8 +-- spec/Memio/Model/Phpdoc/LicensePhpdocSpec.php | 8 +-- spec/Memio/Model/Phpdoc/MethodPhpdocSpec.php | 10 ++-- spec/Memio/Model/Phpdoc/ParameterTagSpec.php | 4 +- .../Memio/Model/Phpdoc/PropertyPhpdocSpec.php | 4 +- .../Model/Phpdoc/StructurePhpdocSpec.php | 8 +-- spec/Memio/Model/Phpdoc/VariableTagSpec.php | 4 +- spec/Memio/Model/PropertySpec.php | 12 ++--- spec/Memio/Model/TypeSpec.php | 50 +++++++++---------- 18 files changed, 110 insertions(+), 110 deletions(-) diff --git a/spec/Memio/Model/ArgumentSpec.php b/spec/Memio/Model/ArgumentSpec.php index 0e1971b..10717a0 100644 --- a/spec/Memio/Model/ArgumentSpec.php +++ b/spec/Memio/Model/ArgumentSpec.php @@ -17,22 +17,22 @@ class ArgumentSpec extends ObjectBehavior { - function let() + function let(): void { $this->beConstructedWith('array', 'lines'); } - function it_has_a_type() + function it_has_a_type(): void { $this->type->name->shouldBe('array'); } - function it_has_a_name() + function it_has_a_name(): void { $this->name->shouldBe('lines'); } - function it_can_have_default_value() + function it_can_have_default_value(): void { $this->defaultValue->shouldBe(null); @@ -43,7 +43,7 @@ function it_can_have_default_value() $this->defaultValue->shouldBe(null); } - function it_can_be_variadic() + function it_can_be_variadic(): void { $this->isVariadic()->shouldBe(false); diff --git a/spec/Memio/Model/ConstantSpec.php b/spec/Memio/Model/ConstantSpec.php index a16b047..e5097f7 100644 --- a/spec/Memio/Model/ConstantSpec.php +++ b/spec/Memio/Model/ConstantSpec.php @@ -20,17 +20,17 @@ class ConstantSpec extends ObjectBehavior const NAME = 'MY_CONSTANT'; const VALUE = "'my string value'"; - function let() + function let(): void { $this->beConstructedWith(self::NAME, self::VALUE); } - function it_has_a_name() + function it_has_a_name(): void { $this->name->shouldBe(self::NAME); } - function it_has_a_value() + function it_has_a_value(): void { $this->value->shouldBe(self::VALUE); } diff --git a/spec/Memio/Model/ContractSpec.php b/spec/Memio/Model/ContractSpec.php index e2fc8e0..5c46418 100644 --- a/spec/Memio/Model/ContractSpec.php +++ b/spec/Memio/Model/ContractSpec.php @@ -25,53 +25,53 @@ class ContractSpec extends ObjectBehavior const NAME = 'MyInterface'; const NAMESPACE_ = 'Vendor\Project'; - function let() + function let(): void { $this->beConstructedWith(self::FULLY_QUALIFIED_NAME); } - function it_is_a_structure() + function it_is_a_structure(): void { $this->shouldImplement('Memio\Model\Structure'); } - function it_has_a_fully_qualified_name() + function it_has_a_fully_qualified_name(): void { $this->fullyQualifiedName->fullyQualifiedName->shouldBe(self::FULLY_QUALIFIED_NAME); } - function it_has_a_name() + function it_has_a_name(): void { $this->getName()->shouldBe(self::NAME); } - function it_has_a_namespace() + function it_has_a_namespace(): void { $this->getNamespace()->shouldBe(self::NAMESPACE_); } - function it_can_have_phpdoc(StructurePhpdoc $phpdoc) + function it_can_have_phpdoc(StructurePhpdoc $phpdoc): void { $this->structurePhpdoc->shouldBe(null); $this->setPhpdoc($phpdoc); $this->structurePhpdoc->shouldBe($phpdoc); } - function it_can_extend_contracts(Contract $contract) + function it_can_extend_contracts(Contract $contract): void { $this->contracts->shouldBe([]); $this->extend($contract); $this->contracts->shouldBe([$contract]); } - function it_can_have_constants(Constant $constant) + function it_can_have_constants(Constant $constant): void { $this->constants->shouldBe([]); $this->addConstant($constant); $this->constants->shouldBe([$constant]); } - function it_can_have_methods(Method $method) + function it_can_have_methods(Method $method): void { $this->methods->shouldBe([]); $this->addMethod($method); diff --git a/spec/Memio/Model/FileSpec.php b/spec/Memio/Model/FileSpec.php index b248d2e..006031b 100644 --- a/spec/Memio/Model/FileSpec.php +++ b/spec/Memio/Model/FileSpec.php @@ -24,17 +24,17 @@ class FileSpec extends ObjectBehavior const NAMESPACE_ = 'Vendor\Project'; const CLASSNAME = 'MyClass'; - function let() + function let(): void { $this->beConstructedWith(self::FILENAME); } - function it_has_a_filename() + function it_has_a_filename(): void { $this->filename->shouldBe(self::FILENAME); } - function it_can_have_license_phpdoc(LicensePhpdoc $licensePhpdoc) + function it_can_have_license_phpdoc(LicensePhpdoc $licensePhpdoc): void { $this->licensePhpdoc->shouldBe(null); @@ -45,7 +45,7 @@ function it_can_have_license_phpdoc(LicensePhpdoc $licensePhpdoc) $this->licensePhpdoc->shouldBe(null); } - function it_has_a_namespace(Structure $structure) + function it_has_a_namespace(Structure $structure): void { $structure->getNamespace()->willReturn(self::NAMESPACE_); @@ -54,14 +54,14 @@ function it_has_a_namespace(Structure $structure) $this->structure->getNamespace()->shouldBe(self::NAMESPACE_); } - function it_can_have_fully_qualified_names(FullyQualifiedName $fullyQualifiedName) + function it_can_have_fully_qualified_names(FullyQualifiedName $fullyQualifiedName): void { $this->fullyQualifiedNames->shouldBe([]); $this->addFullyQualifiedName($fullyQualifiedName); $this->fullyQualifiedNames->shouldBe([$fullyQualifiedName]); } - function it_has_a_structure(Structure $structure) + function it_has_a_structure(Structure $structure): void { $this->setStructure($structure); diff --git a/spec/Memio/Model/FullyQualifiedNameSpec.php b/spec/Memio/Model/FullyQualifiedNameSpec.php index 2e6c41a..9201855 100644 --- a/spec/Memio/Model/FullyQualifiedNameSpec.php +++ b/spec/Memio/Model/FullyQualifiedNameSpec.php @@ -17,27 +17,27 @@ class FullyQualifiedNameSpec extends ObjectBehavior { - function let() + function let(): void { $this->beConstructedWith('Vendor\Project\MyClass'); } - function it_has_fully_qualified_classname() + function it_has_fully_qualified_classname(): void { $this->fullyQualifiedName->shouldBe('Vendor\Project\MyClass'); } - function it_has_name() + function it_has_name(): void { $this->getName()->shouldBe('MyClass'); } - function it_has_namespace() + function it_has_namespace(): void { $this->namespace->shouldBe('Vendor\Project'); } - function it_can_have_an_alias() + function it_can_have_an_alias(): void { $this->hasAlias()->shouldBe(false); $this->getName()->shouldBe('MyClass'); @@ -51,7 +51,7 @@ function it_can_have_an_alias() $this->getName()->shouldBe('MyClass'); } - function it_normalizes_float_name() + function it_normalizes_float_name(): void { $this->beConstructedWith('float'); diff --git a/spec/Memio/Model/MethodSpec.php b/spec/Memio/Model/MethodSpec.php index 5cc3209..94cbe04 100644 --- a/spec/Memio/Model/MethodSpec.php +++ b/spec/Memio/Model/MethodSpec.php @@ -21,24 +21,24 @@ class MethodSpec extends ObjectBehavior { const NAME = '__construct'; - function let() + function let(): void { $this->beConstructedWith(self::NAME); } - function it_has_a_name() + function it_has_a_name(): void { $this->name->shouldBe(self::NAME); } - function it_can_have_phpdoc(MethodPhpdoc $phpdoc) + function it_can_have_phpdoc(MethodPhpdoc $phpdoc): void { $this->methodPhpdoc->shouldBe(null); $this->setPhpdoc($phpdoc); $this->methodPhpdoc->shouldBe($phpdoc); } - function it_can_be_abstract() + function it_can_be_abstract(): void { $this->isAbstract->shouldBe(false); @@ -49,7 +49,7 @@ function it_can_be_abstract() $this->isAbstract->shouldBe(false); } - function it_can_be_final() + function it_can_be_final(): void { $this->isFinal->shouldBe(false); @@ -60,7 +60,7 @@ function it_can_be_final() $this->isFinal->shouldBe(false); } - function it_can_have_visibility() + function it_can_have_visibility(): void { $this->visibility->shouldBe('public'); @@ -77,7 +77,7 @@ function it_can_have_visibility() $this->visibility->shouldBe('public'); } - function it_can_have_staticness() + function it_can_have_staticness(): void { $this->isStatic->shouldBe(false); @@ -88,21 +88,21 @@ function it_can_have_staticness() $this->isStatic->shouldBe(false); } - function it_can_have_arguments(Argument $argument) + function it_can_have_arguments(Argument $argument): void { $this->arguments->shouldBe([]); $this->addArgument($argument); $this->arguments->shouldBe([$argument]); } - function it_can_have_a_return_type() + function it_can_have_a_return_type(): void { $this->returnType->shouldBe(null); $this->setReturnType('array'); $this->returnType->shouldBe('array'); } - function it_can_have_a_body() + function it_can_have_a_body(): void { $body = <<<'EOT' $length = strlen('Nobody expects the spanish inquisition'); diff --git a/spec/Memio/Model/ObjektSpec.php b/spec/Memio/Model/ObjektSpec.php index 79a0e68..b0de5a2 100644 --- a/spec/Memio/Model/ObjektSpec.php +++ b/spec/Memio/Model/ObjektSpec.php @@ -27,39 +27,39 @@ class ObjektSpec extends ObjectBehavior const NAME = 'MyClass'; const NAMESPACE_ = 'Vendor\Project'; - function let() + function let(): void { $this->beConstructedWith(self::FULLY_QUALIFIED_NAME); } - function it_is_a_structure() + function it_is_a_structure(): void { $this->shouldImplement('Memio\Model\Structure'); } - function it_has_a_fully_qualified_name() + function it_has_a_fully_qualified_name(): void { $this->getFullyQualifiedName()->fullyQualifiedName->shouldBe(self::FULLY_QUALIFIED_NAME); } - function it_has_a_name() + function it_has_a_name(): void { $this->getName()->shouldBe(self::NAME); } - function it_has_a_namespace() + function it_has_a_namespace(): void { $this->getNamespace()->shouldBe(self::NAMESPACE_); } - function it_can_have_phpdoc(StructurePhpdoc $phpdoc) + function it_can_have_phpdoc(StructurePhpdoc $phpdoc): void { $this->structurePhpdoc->shouldBe(null); $this->setPhpdoc($phpdoc); $this->structurePhpdoc->shouldBe($phpdoc); } - function it_can_be_abstract() + function it_can_be_abstract(): void { $this->isAbstract->shouldBe(false); $this->makeAbstract(); @@ -68,7 +68,7 @@ function it_can_be_abstract() $this->isAbstract->shouldBe(false); } - function it_can_be_final() + function it_can_be_final(): void { $this->isFinal->shouldBe(false); $this->makeFinal(); @@ -77,7 +77,7 @@ function it_can_be_final() $this->isFinal->shouldBe(false); } - function it_can_have_a_parent(Objekt $parent) + function it_can_have_a_parent(Objekt $parent): void { $this->hasParent()->shouldBe(false); $this->parent->shouldBe(null); @@ -91,28 +91,28 @@ function it_can_have_a_parent(Objekt $parent) $this->parent->shouldBe(null); } - function it_can_implement_contracts(Contract $contract) + function it_can_implement_contracts(Contract $contract): void { $this->contracts->shouldBe([]); $this->implement($contract); $this->contracts->shouldBe([$contract]); } - function it_can_have_constants(Constant $constant) + function it_can_have_constants(Constant $constant): void { $this->constants->shouldBe([]); $this->addConstant($constant); $this->constants->shouldBe([$constant]); } - function it_can_have_properties(Property $property) + function it_can_have_properties(Property $property): void { $this->properties->shouldBe([]); $this->addProperty($property); $this->properties->shouldBe([$property]); } - function it_can_have_methods(Method $method) + function it_can_have_methods(Method $method): void { $this->methods->shouldBe([]); $this->addMethod($method); diff --git a/spec/Memio/Model/Phpdoc/ApiTagSpec.php b/spec/Memio/Model/Phpdoc/ApiTagSpec.php index d079f9e..c7948c3 100644 --- a/spec/Memio/Model/Phpdoc/ApiTagSpec.php +++ b/spec/Memio/Model/Phpdoc/ApiTagSpec.php @@ -17,7 +17,7 @@ class ApiTagSpec extends ObjectBehavior { - function it_can_have_a_since_version() + function it_can_have_a_since_version(): void { $this->beConstructedWith('v2.1'); diff --git a/spec/Memio/Model/Phpdoc/DeprecationTagSpec.php b/spec/Memio/Model/Phpdoc/DeprecationTagSpec.php index 9679106..b12544f 100644 --- a/spec/Memio/Model/Phpdoc/DeprecationTagSpec.php +++ b/spec/Memio/Model/Phpdoc/DeprecationTagSpec.php @@ -17,13 +17,13 @@ class DeprecationTagSpec extends ObjectBehavior { - function it_can_be_just_a_tag() + function it_can_be_just_a_tag(): void { $this->version->shouldBe(null); $this->description->shouldBe(null); } - function it_can_have_a_version() + function it_can_have_a_version(): void { $this->beConstructedWith('v2.1'); @@ -31,7 +31,7 @@ function it_can_have_a_version() $this->description->shouldBe(null); } - function it_can_have_a_description() + function it_can_have_a_description(): void { $this->beConstructedWith('v2.1', 'Use Objekt#myMethod instead'); diff --git a/spec/Memio/Model/Phpdoc/DescriptionSpec.php b/spec/Memio/Model/Phpdoc/DescriptionSpec.php index b873601..586c6f3 100644 --- a/spec/Memio/Model/Phpdoc/DescriptionSpec.php +++ b/spec/Memio/Model/Phpdoc/DescriptionSpec.php @@ -19,24 +19,24 @@ class DescriptionSpec extends ObjectBehavior { const SHORT_DESCRIPTION = 'This is a short description'; - function let() + function let(): void { $this->beConstructedWith(self::SHORT_DESCRIPTION); } - function it_has_a_short_description() + function it_has_a_short_description(): void { $this->lines->shouldBe([self::SHORT_DESCRIPTION]); } - function it_can_have_empty_lines() + function it_can_have_empty_lines(): void { $this->addEmptyLine(); $this->lines->shouldBe([self::SHORT_DESCRIPTION, '']); } - function it_can_have_long_description() + function it_can_have_long_description(): void { $longDescription = [ 'Long descriptions can span on many lines', diff --git a/spec/Memio/Model/Phpdoc/LicensePhpdocSpec.php b/spec/Memio/Model/Phpdoc/LicensePhpdocSpec.php index 1e42250..7fdab77 100644 --- a/spec/Memio/Model/Phpdoc/LicensePhpdocSpec.php +++ b/spec/Memio/Model/Phpdoc/LicensePhpdocSpec.php @@ -21,22 +21,22 @@ class LicensePhpdocSpec extends ObjectBehavior const AUTHOR_NAME = 'Loïc Faugeron'; const AUTHOR_EMAIL = 'faugeron.loic@gmail.com'; - function let() + function let(): void { $this->beConstructedWith(self::PROJECT_NAME, self::AUTHOR_NAME, self::AUTHOR_EMAIL); } - function it_has_project_name() + function it_has_project_name(): void { $this->projectName->shouldBe(self::PROJECT_NAME); } - function it_has_author_name() + function it_has_author_name(): void { $this->authorName->shouldBe(self::AUTHOR_NAME); } - function it_has_author_email() + function it_has_author_email(): void { $this->authorEmail->shouldBe(self::AUTHOR_EMAIL); } diff --git a/spec/Memio/Model/Phpdoc/MethodPhpdocSpec.php b/spec/Memio/Model/Phpdoc/MethodPhpdocSpec.php index 57707fa..e13cc32 100644 --- a/spec/Memio/Model/Phpdoc/MethodPhpdocSpec.php +++ b/spec/Memio/Model/Phpdoc/MethodPhpdocSpec.php @@ -21,33 +21,33 @@ class MethodPhpdocSpec extends ObjectBehavior { - function it_can_be_empty() + function it_can_be_empty(): void { $this->isEmpty()->shouldBe(true); } - function it_can_have_description(Description $description) + function it_can_have_description(Description $description): void { $this->setDescription($description); $this->description->shouldBe($description); $this->isEmpty(false); } - function it_can_have_parameters(ParameterTag $parameterTag) + function it_can_have_parameters(ParameterTag $parameterTag): void { $this->addParameterTag($parameterTag); $this->parameterTags->shouldBe([$parameterTag]); $this->isEmpty(false); } - function it_can_be_tagged_as_api(ApiTag $apiTag) + function it_can_be_tagged_as_api(ApiTag $apiTag): void { $this->setApiTag($apiTag); $this->apiTag->shouldBe($apiTag); $this->isEmpty()->shouldBe(false); } - function it_can_be_tagged_as_deprecated(DeprecationTag $deprecationTag) + function it_can_be_tagged_as_deprecated(DeprecationTag $deprecationTag): void { $this->setDeprecationTag($deprecationTag); $this->deprecationTag->shouldBe($deprecationTag); diff --git a/spec/Memio/Model/Phpdoc/ParameterTagSpec.php b/spec/Memio/Model/Phpdoc/ParameterTagSpec.php index 4fedb9f..0c69c30 100644 --- a/spec/Memio/Model/Phpdoc/ParameterTagSpec.php +++ b/spec/Memio/Model/Phpdoc/ParameterTagSpec.php @@ -17,7 +17,7 @@ class ParameterTagSpec extends ObjectBehavior { - function it_has_a_type_and_a_name() + function it_has_a_type_and_a_name(): void { $this->beConstructedWith('Vendor\Project\MyClass', 'myClass'); @@ -25,7 +25,7 @@ function it_has_a_type_and_a_name() $this->name->shouldBe('myClass'); } - function it_can_have_a_description() + function it_can_have_a_description(): void { $this->beConstructedWith('Vendor\Project\MyClass', 'myClass', 'description'); diff --git a/spec/Memio/Model/Phpdoc/PropertyPhpdocSpec.php b/spec/Memio/Model/Phpdoc/PropertyPhpdocSpec.php index ebdfdcc..0c9d960 100644 --- a/spec/Memio/Model/Phpdoc/PropertyPhpdocSpec.php +++ b/spec/Memio/Model/Phpdoc/PropertyPhpdocSpec.php @@ -18,12 +18,12 @@ class PropertyPhpdocSpec extends ObjectBehavior { - function it_can_be_empty() + function it_can_be_empty(): void { $this->isEmpty()->shouldBe(true); } - function it_can_have_a_property_tag(VariableTag $variableTag) + function it_can_have_a_property_tag(VariableTag $variableTag): void { $this->setVariableTag($variableTag); $this->variableTag->shouldBe($variableTag); diff --git a/spec/Memio/Model/Phpdoc/StructurePhpdocSpec.php b/spec/Memio/Model/Phpdoc/StructurePhpdocSpec.php index 2ad4546..d430c5f 100644 --- a/spec/Memio/Model/Phpdoc/StructurePhpdocSpec.php +++ b/spec/Memio/Model/Phpdoc/StructurePhpdocSpec.php @@ -20,26 +20,26 @@ class StructurePhpdocSpec extends ObjectBehavior { - function it_can_be_empty() + function it_can_be_empty(): void { $this->isEmpty()->shouldBe(true); } - function it_can_have_description(Description $description) + function it_can_have_description(Description $description): void { $this->setDescription($description); $this->description->shouldBe($description); $this->isEmpty(false); } - function it_can_be_tagged_as_api(ApiTag $apiTag) + function it_can_be_tagged_as_api(ApiTag $apiTag): void { $this->setApiTag($apiTag); $this->apiTag->shouldBe($apiTag); $this->isEmpty()->shouldBe(false); } - function it_can_be_tagged_as_deprecated(DeprecationTag $deprecationTag) + function it_can_be_tagged_as_deprecated(DeprecationTag $deprecationTag): void { $this->setDeprecationTag($deprecationTag); $this->deprecationTag->shouldBe($deprecationTag); diff --git a/spec/Memio/Model/Phpdoc/VariableTagSpec.php b/spec/Memio/Model/Phpdoc/VariableTagSpec.php index 0ade7e5..0282af7 100644 --- a/spec/Memio/Model/Phpdoc/VariableTagSpec.php +++ b/spec/Memio/Model/Phpdoc/VariableTagSpec.php @@ -17,14 +17,14 @@ class VariableTagSpec extends ObjectBehavior { - function it_has_a_type() + function it_has_a_type(): void { $this->beConstructedWith('string'); $this->type->name->shouldBe('string'); } - function it_can_have_a_fully_qualified_name() + function it_can_have_a_fully_qualified_name(): void { $this->beConstructedWith('Vendor\Project\MyClass'); diff --git a/spec/Memio/Model/PropertySpec.php b/spec/Memio/Model/PropertySpec.php index 1a144ae..28cbdcd 100644 --- a/spec/Memio/Model/PropertySpec.php +++ b/spec/Memio/Model/PropertySpec.php @@ -20,24 +20,24 @@ class PropertySpec extends ObjectBehavior { const NAME = 'dateTime'; - function let() + function let(): void { $this->beConstructedWith(self::NAME); } - function it_has_a_name() + function it_has_a_name(): void { $this->name->shouldBe(self::NAME); } - function it_can_have_phpdoc(PropertyPhpdoc $phpdoc) + function it_can_have_phpdoc(PropertyPhpdoc $phpdoc): void { $this->propertyPhpdoc->shouldBe(null); $this->setPhpdoc($phpdoc); $this->propertyPhpdoc->shouldBe($phpdoc); } - function it_has_visibility() + function it_has_visibility(): void { $this->visibility->shouldBe('private'); @@ -51,7 +51,7 @@ function it_has_visibility() $this->visibility->shouldBe('private'); } - function it_can_have_staticness() + function it_can_have_staticness(): void { $this->isStatic->shouldBe(false); @@ -62,7 +62,7 @@ function it_can_have_staticness() $this->isStatic->shouldBe(false); } - function it_can_have_a_default_value() + function it_can_have_a_default_value(): void { $this->defaultValue->shouldBe(null); $this->setDefaultValue('null'); diff --git a/spec/Memio/Model/TypeSpec.php b/spec/Memio/Model/TypeSpec.php index e163b45..43e79a5 100644 --- a/spec/Memio/Model/TypeSpec.php +++ b/spec/Memio/Model/TypeSpec.php @@ -17,7 +17,7 @@ class TypeSpec extends ObjectBehavior { - function it_can_be_an_object() + function it_can_be_an_object(): void { $this->beConstructedWith('Vendor\Project\MyClass'); @@ -25,84 +25,84 @@ function it_can_be_an_object() $this->isObject()->shouldBe(true); } - function it_can_have_a_type_hint_if_it_is_an_object() + function it_can_have_a_type_hint_if_it_is_an_object(): void { $this->beConstructedWith('DateTime'); $this->hasTypeHint()->shouldBe(true); } - function it_can_have_a_type_hint_if_it_is_an_array() + function it_can_have_a_type_hint_if_it_is_an_array(): void { $this->beConstructedWith('array'); $this->hasTypeHint()->shouldBe(true); } - function it_can_have_a_type_hint_if_it_is_a_callable() + function it_can_have_a_type_hint_if_it_is_a_callable(): void { $this->beConstructedWith('callable'); $this->hasTypeHint()->shouldBe(true); } - function it_can_have_a_type_hint_if_it_is_a_string() + function it_can_have_a_type_hint_if_it_is_a_string(): void { $this->beConstructedWith('string'); $this->hasTypeHint()->shouldBe(true); } - function it_can_have_a_type_hint_if_it_is_an_integer() + function it_can_have_a_type_hint_if_it_is_an_integer(): void { $this->beConstructedWith('int'); $this->hasTypeHint()->shouldBe(true); } - function it_can_have_a_type_hint_if_it_is_a_float() + function it_can_have_a_type_hint_if_it_is_a_float(): void { $this->beconstructedwith('float'); $this->hastypehint()->shouldbe(true); } - function it_can_have_a_type_hint_if_it_is_a_boolean() + function it_can_have_a_type_hint_if_it_is_a_boolean(): void { $this->beConstructedWith('bool'); $this->hasTypeHint()->shouldBe(true); } - function it_can_have_a_type_hint_if_it_is_a_string_from_php_7_0() + function it_can_have_a_type_hint_if_it_is_a_string_from_php_7_0(): void { $this->beConstructedWith('string'); $this->hasTypeHint()->shouldBe(version_compare(PHP_VERSION, '7.0.0') >= 0); } - function it_can_have_a_type_hint_if_it_is_an_integer_from_php_7_0() + function it_can_have_a_type_hint_if_it_is_an_integer_from_php_7_0(): void { $this->beConstructedWith('int'); $this->hasTypeHint()->shouldBe(version_compare(PHP_VERSION, '7.0.0') >= 0); } - function it_can_have_a_type_hint_if_it_is_a_float_from_php_7_0() + function it_can_have_a_type_hint_if_it_is_a_float_from_php_7_0(): void { $this->beConstructedWith('float'); $this->hasTypeHint()->shouldBe(version_compare(PHP_VERSION, '7.0.0') >= 0); } - function it_can_have_a_type_hint_if_it_is_a_boolean_from_php_7_0() + function it_can_have_a_type_hint_if_it_is_a_boolean_from_php_7_0(): void { $this->beConstructedWith('bool'); $this->hasTypeHint()->shouldBe(version_compare(PHP_VERSION, '7.0.0') >= 0); } - function it_can_be_an_array() + function it_can_be_an_array(): void { $this->beConstructedWith('array'); @@ -110,7 +110,7 @@ function it_can_be_an_array() $this->isObject()->shouldBe(false); } - function it_can_be_a_callable() + function it_can_be_a_callable(): void { $this->beConstructedWith('callable'); @@ -118,7 +118,7 @@ function it_can_be_a_callable() $this->isObject()->shouldBe(false); } - function it_can_be_a_string() + function it_can_be_a_string(): void { $this->beConstructedWith('string'); @@ -126,7 +126,7 @@ function it_can_be_a_string() $this->isObject()->shouldBe(false); } - function it_can_be_a_boolean() + function it_can_be_a_boolean(): void { $this->beConstructedWith('bool'); @@ -134,7 +134,7 @@ function it_can_be_a_boolean() $this->isObject()->shouldBe(false); } - function it_normalizes_boolean_name() + function it_normalizes_boolean_name(): void { $this->beConstructedWith('boolean'); @@ -142,7 +142,7 @@ function it_normalizes_boolean_name() $this->isObject()->shouldBe(false); } - function it_can_be_a_resource() + function it_can_be_a_resource(): void { $this->beConstructedWith('resource'); @@ -150,7 +150,7 @@ function it_can_be_a_resource() $this->isObject()->shouldBe(false); } - function it_can_be_an_integer() + function it_can_be_an_integer(): void { $this->beConstructedWith('int'); @@ -158,7 +158,7 @@ function it_can_be_an_integer() $this->isObject()->shouldBe(false); } - function it_normalizes_integer_name() + function it_normalizes_integer_name(): void { $this->beConstructedWith('integer'); @@ -166,7 +166,7 @@ function it_normalizes_integer_name() $this->isObject()->shouldBe(false); } - function it_can_be_a_float() + function it_can_be_a_float(): void { $this->beConstructedWith('float'); @@ -174,7 +174,7 @@ function it_can_be_a_float() $this->isObject()->shouldBe(false); } - function it_normalizes_float_name() + function it_normalizes_float_name(): void { $this->beConstructedWith('double'); @@ -182,7 +182,7 @@ function it_normalizes_float_name() $this->isObject()->shouldBe(false); } - function it_can_be_null() + function it_can_be_null(): void { $this->beConstructedWith('null'); @@ -190,7 +190,7 @@ function it_can_be_null() $this->isObject()->shouldBe(false); } - function it_normalizes_null_name() + function it_normalizes_null_name(): void { $this->beConstructedWith('NULL'); @@ -198,7 +198,7 @@ function it_normalizes_null_name() $this->isObject()->shouldBe(false); } - function it_can_be_unknown() + function it_can_be_unknown(): void { $this->beConstructedWith('mixed'); From eb68b83cc7c0de1f6093c4579605d290ca2ae2c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Faugeron?= Date: Fri, 6 Feb 2026 07:20:08 +0000 Subject: [PATCH 05/18] chore: Dropped support for PHP 7.2 (now minimum version is PHP 7.3) --- .php-cs-fixer.dist.php | 2 +- CHANGELOG.md | 4 ++++ composer.json | 4 ++-- phpstan.neon.dist | 2 +- rector.php | 2 +- src/Memio/Model/Property.php | 2 +- 6 files changed, 10 insertions(+), 6 deletions(-) diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index e0e4ff8..f411430 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -35,7 +35,7 @@ return (new PhpCsFixer\Config()) ->setRules([ '@Symfony' => true, - '@PHP71Migration' => true, + '@PHP73Migration' => true, '@PHP71Migration:risky' => true, // [Symfony] defaults to `camelCase`, we set it to `snake_case` (phpspec style) diff --git a/CHANGELOG.md b/CHANGELOG.md index ccfab59..2e4cb90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # CHANGELOG +## 4.0.0: PHP 7.3 requirement + +Dropped support for PHP <7.3 + ## 3.0.2: Dockerised dev environment * setup Github Actions diff --git a/composer.json b/composer.json index 5965ac5..ec42edf 100644 --- a/composer.json +++ b/composer.json @@ -17,11 +17,11 @@ "Memio\\Model\\": "src/Memio/Model" }}, "require": { - "php": "^7.2 || ^8.0" + "php": "^7.3 || ^8.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.19.3", - "phpspec/phpspec": "^6.1 || ^7.0", + "phpspec/phpspec": "^7.0", "phpstan/phpstan": "1.12.32", "rector/rector": "^1.2.10", "rector/swiss-knife": "^2.3" diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 7319f18..8038747 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -3,6 +3,6 @@ includes: parameters: level: 0 - phpVersion: 70200 + phpVersion: 70300 paths: - src/ diff --git a/rector.php b/rector.php index f2db8c0..41ba586 100644 --- a/rector.php +++ b/rector.php @@ -23,7 +23,7 @@ ]) ->withSets([ // —— PHP —————————————————————————————————————————————————————————————— - SetList::PHP_72, + SetList::PHP_73, ]) ->withRules([ ]); diff --git a/src/Memio/Model/Property.php b/src/Memio/Model/Property.php index 059fe3e..61702a4 100644 --- a/src/Memio/Model/Property.php +++ b/src/Memio/Model/Property.php @@ -57,7 +57,7 @@ public function makeStatic(): self /** * @api */ - public function removeStatic() + public function removeStatic(): void { $this->isStatic = false; } From 98bf890b7d19e80ec5015b782f83993b19752773 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Faugeron?= Date: Mon, 9 Feb 2026 07:22:29 +0000 Subject: [PATCH 06/18] chore: Fixed CS --- spec/Memio/Model/MethodSpec.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/Memio/Model/MethodSpec.php b/spec/Memio/Model/MethodSpec.php index 94cbe04..8b2c384 100644 --- a/spec/Memio/Model/MethodSpec.php +++ b/spec/Memio/Model/MethodSpec.php @@ -105,8 +105,8 @@ function it_can_have_a_return_type(): void function it_can_have_a_body(): void { $body = <<<'EOT' - $length = strlen('Nobody expects the spanish inquisition'); -EOT; + $length = strlen('Nobody expects the spanish inquisition'); + EOT; $this->setBody($body); $this->body->shouldBe($body); } From da63463c03c8b49a8e4d728699b89ee91d17481d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Faugeron?= Date: Mon, 9 Feb 2026 07:24:09 +0000 Subject: [PATCH 07/18] chore: Dropped support for PHP 7.3 (now minimum version is PHP 7.4) --- .php-cs-fixer.dist.php | 4 ++-- CHANGELOG.md | 4 ++-- composer.json | 2 +- phpstan.neon.dist | 2 +- rector.php | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index f411430..1d77ce4 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -35,8 +35,8 @@ return (new PhpCsFixer\Config()) ->setRules([ '@Symfony' => true, - '@PHP73Migration' => true, - '@PHP71Migration:risky' => true, + '@PHP74Migration' => true, + '@PHP74Migration:risky' => true, // [Symfony] defaults to `camelCase`, we set it to `snake_case` (phpspec style) 'php_unit_method_casing' => ['case' => 'snake_case'], diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e4cb90..4745f4d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,8 @@ # CHANGELOG -## 4.0.0: PHP 7.3 requirement +## 4.0.0: PHP 7.4 requirement -Dropped support for PHP <7.3 +Dropped support for PHP <7.4 ## 3.0.2: Dockerised dev environment diff --git a/composer.json b/composer.json index ec42edf..1f1d241 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ "Memio\\Model\\": "src/Memio/Model" }}, "require": { - "php": "^7.3 || ^8.0" + "php": "^7.4 || ^8.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.19.3", diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 8038747..1721f77 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -3,6 +3,6 @@ includes: parameters: level: 0 - phpVersion: 70300 + phpVersion: 70400 paths: - src/ diff --git a/rector.php b/rector.php index 41ba586..7bed747 100644 --- a/rector.php +++ b/rector.php @@ -23,7 +23,7 @@ ]) ->withSets([ // —— PHP —————————————————————————————————————————————————————————————— - SetList::PHP_73, + SetList::PHP_74, ]) ->withRules([ ]); From f0c6ec7f29d77a57f13c98bb114bae36ae540699 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Faugeron?= Date: Mon, 9 Feb 2026 07:34:06 +0000 Subject: [PATCH 08/18] feat: add support for typed class properties --- CHANGELOG.md | 4 ++++ spec/Memio/Model/PropertySpec.php | 11 +++++++++++ src/Memio/Model/Property.php | 19 +++++++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4745f4d..f7ec142 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ Dropped support for PHP <7.4 +New features: + +* added support for class property types + ## 3.0.2: Dockerised dev environment * setup Github Actions diff --git a/spec/Memio/Model/PropertySpec.php b/spec/Memio/Model/PropertySpec.php index 28cbdcd..301c4ab 100644 --- a/spec/Memio/Model/PropertySpec.php +++ b/spec/Memio/Model/PropertySpec.php @@ -62,6 +62,17 @@ function it_can_have_staticness(): void $this->isStatic->shouldBe(false); } + function it_can_have_a_type(): void + { + $this->type->shouldBe(null); + + $this->setType('int'); + $this->type->name->shouldBe('int'); + + $this->removeType(); + $this->type->shouldBe(null); + } + function it_can_have_a_default_value(): void { $this->defaultValue->shouldBe(null); diff --git a/src/Memio/Model/Property.php b/src/Memio/Model/Property.php index 61702a4..ff3cb5a 100644 --- a/src/Memio/Model/Property.php +++ b/src/Memio/Model/Property.php @@ -21,6 +21,7 @@ class Property { public $name; + public $type; public $propertyPhpdoc; public $isStatic = false; public $visibility = 'private'; @@ -92,6 +93,24 @@ public function makePublic(): self return $this; } + /** + * @api + */ + public function setType(string $type): self + { + $this->type = new Type($type); + + return $this; + } + + /** + * @api + */ + public function removeType(): void + { + $this->type = null; + } + /** * @api */ From ec9d36df71e88cb3b9591ee0a09aef55ee079efe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Faugeron?= Date: Mon, 9 Feb 2026 08:20:21 +0000 Subject: [PATCH 09/18] chore: added typed class properties to codebase --- src/Memio/Model/Argument.php | 8 ++++---- src/Memio/Model/Constant.php | 4 ++-- src/Memio/Model/Contract.php | 10 +++++----- src/Memio/Model/File.php | 8 ++++---- src/Memio/Model/FullyQualifiedName.php | 8 ++++---- src/Memio/Model/Method.php | 18 +++++++++--------- src/Memio/Model/Objekt.php | 18 +++++++++--------- src/Memio/Model/Phpdoc/ApiTag.php | 2 +- src/Memio/Model/Phpdoc/DeprecationTag.php | 4 ++-- src/Memio/Model/Phpdoc/Description.php | 2 +- src/Memio/Model/Phpdoc/LicensePhpdoc.php | 6 +++--- src/Memio/Model/Phpdoc/MethodPhpdoc.php | 14 +++++++------- src/Memio/Model/Phpdoc/ParameterTag.php | 6 +++--- src/Memio/Model/Phpdoc/PropertyPhpdoc.php | 2 +- src/Memio/Model/Phpdoc/ReturnTag.php | 2 +- src/Memio/Model/Phpdoc/StructurePhpdoc.php | 6 +++--- src/Memio/Model/Phpdoc/ThrowTag.php | 2 +- src/Memio/Model/Phpdoc/VariableTag.php | 2 +- src/Memio/Model/Property.php | 12 ++++++------ src/Memio/Model/Type.php | 6 +++--- 20 files changed, 70 insertions(+), 70 deletions(-) diff --git a/src/Memio/Model/Argument.php b/src/Memio/Model/Argument.php index f17bda0..eab7173 100644 --- a/src/Memio/Model/Argument.php +++ b/src/Memio/Model/Argument.php @@ -18,10 +18,10 @@ */ class Argument { - public $type; - public $name; - public $defaultValue; - public $isVariadic = false; + public Type $type; + public string $name; + public ?string $defaultValue = null; + public bool $isVariadic = false; /** * @api diff --git a/src/Memio/Model/Constant.php b/src/Memio/Model/Constant.php index 6e223cb..fb37601 100644 --- a/src/Memio/Model/Constant.php +++ b/src/Memio/Model/Constant.php @@ -18,8 +18,8 @@ */ class Constant { - public $name; - public $value; + public string $name; + public string $value; /** * @api diff --git a/src/Memio/Model/Contract.php b/src/Memio/Model/Contract.php index 35b9fd7..97520a1 100644 --- a/src/Memio/Model/Contract.php +++ b/src/Memio/Model/Contract.php @@ -22,11 +22,11 @@ */ class Contract implements Structure { - public $fullyQualifiedName; - public $structurePhpdoc; - public $contracts = []; - public $constants = []; - public $methods = []; + public FullyQualifiedName $fullyQualifiedName; + public ?StructurePhpdoc $structurePhpdoc = null; + public array $contracts = []; + public array $constants = []; + public array $methods = []; /** * @api diff --git a/src/Memio/Model/File.php b/src/Memio/Model/File.php index 67cfecd..5c78537 100644 --- a/src/Memio/Model/File.php +++ b/src/Memio/Model/File.php @@ -20,10 +20,10 @@ */ class File { - public $filename; - public $licensePhpdoc; - public $fullyQualifiedNames = []; - public $structure; + public string $filename; + public ?LicensePhpdoc $licensePhpdoc = null; + public array $fullyQualifiedNames = []; + public ?Structure $structure = null; /** * @api diff --git a/src/Memio/Model/FullyQualifiedName.php b/src/Memio/Model/FullyQualifiedName.php index ea20570..e649cc5 100644 --- a/src/Memio/Model/FullyQualifiedName.php +++ b/src/Memio/Model/FullyQualifiedName.php @@ -21,10 +21,10 @@ class FullyQualifiedName public const NORMALIZATIONS = [ 'float' => 'double', ]; - public $fullyQualifiedName; - public $name; - public $namespace; - public $alias; + public string $fullyQualifiedName; + public string $name; + public string $namespace; + public ?string $alias = null; /** * @api diff --git a/src/Memio/Model/Method.php b/src/Memio/Model/Method.php index 7084fc6..e0709a3 100644 --- a/src/Memio/Model/Method.php +++ b/src/Memio/Model/Method.php @@ -20,15 +20,15 @@ */ class Method { - public $name; - public $methodPhpdoc; - public $isAbstract = false; - public $isFinal = false; - public $visibility = 'public'; - public $isStatic = false; - public $arguments = []; - public $body = ''; - public $returnType; + public string $name; + public ?MethodPhpdoc $methodPhpdoc = null; + public bool $isAbstract = false; + public bool $isFinal = false; + public string $visibility = 'public'; + public bool $isStatic = false; + public array $arguments = []; + public string $body = ''; + public ?string $returnType = null; /** * @api diff --git a/src/Memio/Model/Objekt.php b/src/Memio/Model/Objekt.php index d2848cc..e2259a9 100644 --- a/src/Memio/Model/Objekt.php +++ b/src/Memio/Model/Objekt.php @@ -22,15 +22,15 @@ */ class Objekt implements Structure { - public $fullyQualifiedName; - public $structurePhpdoc; - public $isAbstract = false; - public $isFinal = false; - public $parent; - public $contracts = []; - public $constants = []; - public $properties = []; - public $methods = []; + public FullyQualifiedName $fullyQualifiedName; + public ?StructurePhpdoc $structurePhpdoc = null; + public bool $isAbstract = false; + public bool $isFinal = false; + public ?Objekt $parent = null; + public array $contracts = []; + public array $constants = []; + public array $properties = []; + public array $methods = []; /** * @api diff --git a/src/Memio/Model/Phpdoc/ApiTag.php b/src/Memio/Model/Phpdoc/ApiTag.php index 154704b..39ded2f 100644 --- a/src/Memio/Model/Phpdoc/ApiTag.php +++ b/src/Memio/Model/Phpdoc/ApiTag.php @@ -18,7 +18,7 @@ */ class ApiTag { - public $since; + public ?string $since; /** * @api diff --git a/src/Memio/Model/Phpdoc/DeprecationTag.php b/src/Memio/Model/Phpdoc/DeprecationTag.php index 828ee78..fe0fc7b 100644 --- a/src/Memio/Model/Phpdoc/DeprecationTag.php +++ b/src/Memio/Model/Phpdoc/DeprecationTag.php @@ -18,8 +18,8 @@ */ class DeprecationTag { - public $version; - public $description; + public ?string $version; + public ?string $description; /** * @api diff --git a/src/Memio/Model/Phpdoc/Description.php b/src/Memio/Model/Phpdoc/Description.php index 1209504..0349921 100644 --- a/src/Memio/Model/Phpdoc/Description.php +++ b/src/Memio/Model/Phpdoc/Description.php @@ -15,7 +15,7 @@ class Description { - public $lines = []; + public array $lines = []; /** * @api diff --git a/src/Memio/Model/Phpdoc/LicensePhpdoc.php b/src/Memio/Model/Phpdoc/LicensePhpdoc.php index eda54ac..13e2858 100644 --- a/src/Memio/Model/Phpdoc/LicensePhpdoc.php +++ b/src/Memio/Model/Phpdoc/LicensePhpdoc.php @@ -18,9 +18,9 @@ */ class LicensePhpdoc { - public $projectName; - public $authorName; - public $authorEmail; + public string $projectName; + public string $authorName; + public string $authorEmail; /** * @api diff --git a/src/Memio/Model/Phpdoc/MethodPhpdoc.php b/src/Memio/Model/Phpdoc/MethodPhpdoc.php index 921a49d..45b194e 100644 --- a/src/Memio/Model/Phpdoc/MethodPhpdoc.php +++ b/src/Memio/Model/Phpdoc/MethodPhpdoc.php @@ -18,12 +18,12 @@ */ class MethodPhpdoc { - public $apiTag; - public $deprecationTag; - public $returnTag; - public $description; - public $parameterTags = []; - public $throwTags = []; + public ?ApiTag $apiTag = null; + public ?DeprecationTag $deprecationTag = null; + public ?ReturnTag $returnTag = null; + public ?Description $description = null; + public array $parameterTags = []; + public array $throwTags = []; /** * @api @@ -48,7 +48,7 @@ public function setReturnTag(ReturnTag $returnTag): self /** * @api */ - public function setDescription($description): self + public function setDescription(Description $description): self { $this->description = $description; diff --git a/src/Memio/Model/Phpdoc/ParameterTag.php b/src/Memio/Model/Phpdoc/ParameterTag.php index 2bf367e..a0ad2e5 100644 --- a/src/Memio/Model/Phpdoc/ParameterTag.php +++ b/src/Memio/Model/Phpdoc/ParameterTag.php @@ -20,9 +20,9 @@ */ class ParameterTag { - public $type; - public $name; - public $description; + public Type $type; + public string $name; + public ?string $description; /** * @api diff --git a/src/Memio/Model/Phpdoc/PropertyPhpdoc.php b/src/Memio/Model/Phpdoc/PropertyPhpdoc.php index b8bb24e..6d4494c 100644 --- a/src/Memio/Model/Phpdoc/PropertyPhpdoc.php +++ b/src/Memio/Model/Phpdoc/PropertyPhpdoc.php @@ -18,7 +18,7 @@ */ class PropertyPhpdoc { - public $variableTag; + public ?VariableTag $variableTag = null; /** * @api diff --git a/src/Memio/Model/Phpdoc/ReturnTag.php b/src/Memio/Model/Phpdoc/ReturnTag.php index e0f0b96..d6db11d 100644 --- a/src/Memio/Model/Phpdoc/ReturnTag.php +++ b/src/Memio/Model/Phpdoc/ReturnTag.php @@ -15,7 +15,7 @@ class ReturnTag { - public $type; + public string $type; /** * @api diff --git a/src/Memio/Model/Phpdoc/StructurePhpdoc.php b/src/Memio/Model/Phpdoc/StructurePhpdoc.php index c654870..259e1d5 100644 --- a/src/Memio/Model/Phpdoc/StructurePhpdoc.php +++ b/src/Memio/Model/Phpdoc/StructurePhpdoc.php @@ -18,9 +18,9 @@ */ class StructurePhpdoc { - public $apiTag; - public $deprecationTag; - public $description; + public ?ApiTag $apiTag = null; + public ?DeprecationTag $deprecationTag = null; + public ?Description $description = null; /** * @api diff --git a/src/Memio/Model/Phpdoc/ThrowTag.php b/src/Memio/Model/Phpdoc/ThrowTag.php index 394059b..6faa0de 100644 --- a/src/Memio/Model/Phpdoc/ThrowTag.php +++ b/src/Memio/Model/Phpdoc/ThrowTag.php @@ -15,7 +15,7 @@ class ThrowTag { - public $exception; + public string $exception; /** * @api diff --git a/src/Memio/Model/Phpdoc/VariableTag.php b/src/Memio/Model/Phpdoc/VariableTag.php index ed48589..5d55a59 100644 --- a/src/Memio/Model/Phpdoc/VariableTag.php +++ b/src/Memio/Model/Phpdoc/VariableTag.php @@ -17,7 +17,7 @@ class VariableTag { - public $type; + public Type $type; /** * @api diff --git a/src/Memio/Model/Property.php b/src/Memio/Model/Property.php index ff3cb5a..fd48caf 100644 --- a/src/Memio/Model/Property.php +++ b/src/Memio/Model/Property.php @@ -20,12 +20,12 @@ */ class Property { - public $name; - public $type; - public $propertyPhpdoc; - public $isStatic = false; - public $visibility = 'private'; - public $defaultValue; + public string $name; + public ?Type $type = null; + public ?PropertyPhpdoc $propertyPhpdoc = null; + public bool $isStatic = false; + public string $visibility = 'private'; + public ?string $defaultValue = null; /** * @api diff --git a/src/Memio/Model/Type.php b/src/Memio/Model/Type.php index aee5900..f75fbf8 100644 --- a/src/Memio/Model/Type.php +++ b/src/Memio/Model/Type.php @@ -44,9 +44,9 @@ class Type 'string', ]; - public $name; - public $isObject; - public $hasTypeHint; + public string $name; + public bool $isObject; + public bool $hasTypeHint; /** * @api From ba6ceb5af76bde8ddd5ac4b829c2a44fe2f324fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Faugeron?= Date: Thu, 12 Feb 2026 07:22:14 +0000 Subject: [PATCH 10/18] feat: add support to nullable typehints --- CHANGELOG.md | 1 + spec/Memio/Model/TypeSpec.php | 40 +++++++++++++++++++++++++++++++++++ src/Memio/Model/Type.php | 13 ++++++++++++ 3 files changed, 54 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7ec142..11fe7b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ Dropped support for PHP <7.4 New features: * added support for class property types +* added support for nullable typehints ## 3.0.2: Dockerised dev environment diff --git a/spec/Memio/Model/TypeSpec.php b/spec/Memio/Model/TypeSpec.php index 43e79a5..b0641cb 100644 --- a/spec/Memio/Model/TypeSpec.php +++ b/spec/Memio/Model/TypeSpec.php @@ -23,6 +23,7 @@ function it_can_be_an_object(): void $this->getName()->shouldBe('Vendor\Project\MyClass'); $this->isObject()->shouldBe(true); + $this->isNullable()->shouldBe(false); } function it_can_have_a_type_hint_if_it_is_an_object(): void @@ -205,4 +206,43 @@ function it_can_be_unknown(): void $this->getName()->shouldBe('mixed'); $this->isObject()->shouldBe(false); } + + function it_can_be_a_nullable_object(): void + { + $this->beConstructedWith('?DateTime'); + + $this->getName()->shouldBe('DateTime'); + $this->isObject()->shouldBe(true); + $this->hasTypeHint()->shouldBe(true); + $this->isNullable()->shouldBe(true); + } + + function it_can_be_a_nullable_scalar(): void + { + $this->beConstructedWith('?string'); + + $this->getName()->shouldBe('string'); + $this->isObject()->shouldBe(false); + $this->hasTypeHint()->shouldBe(true); + $this->isNullable()->shouldBe(true); + } + + function it_can_be_a_nullable_array(): void + { + $this->beConstructedWith('?array'); + + $this->getName()->shouldBe('array'); + $this->isObject()->shouldBe(false); + $this->hasTypeHint()->shouldBe(true); + $this->isNullable()->shouldBe(true); + } + + function it_normalizes_nullable_names(): void + { + $this->beConstructedWith('?boolean'); + + $this->getName()->shouldBe('bool'); + $this->isObject()->shouldBe(false); + $this->isNullable()->shouldBe(true); + } } diff --git a/src/Memio/Model/Type.php b/src/Memio/Model/Type.php index f75fbf8..20c848f 100644 --- a/src/Memio/Model/Type.php +++ b/src/Memio/Model/Type.php @@ -47,12 +47,17 @@ class Type public string $name; public bool $isObject; public bool $hasTypeHint; + public bool $isNullable; /** * @api */ public function __construct(string $name) { + $this->isNullable = str_starts_with($name, '?'); + if ($this->isNullable) { + $name = substr($name, 1); + } if (isset(self::NORMALIZATIONS[$name])) { $name = self::NORMALIZATIONS[$name]; } @@ -87,4 +92,12 @@ public function hasTypeHint(): bool { return $this->hasTypeHint; } + + /** + * @api + */ + public function isNullable(): bool + { + return $this->isNullable; + } } From 53d9aab96958252ab155f0058fb7d99e23212b3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Faugeron?= Date: Thu, 12 Feb 2026 17:17:38 +0000 Subject: [PATCH 11/18] chore: Dropped support for PHP 7.4 (now minimum version is PHP 8.0) _AI Disclosure_: used Claude Code (v2.1.39, Opus 4.6), to help with the chores. --- .php-cs-fixer.dist.php | 7 +++++-- CHANGELOG.md | 4 ++-- composer.json | 2 +- phpstan.neon.dist | 2 +- rector.php | 4 ++-- spec/Memio/Model/Phpdoc/DescriptionSpec.php | 2 +- src/Memio/Model/Argument.php | 4 +--- src/Memio/Model/Constant.php | 11 ++++------- src/Memio/Model/File.php | 4 +--- src/Memio/Model/Method.php | 4 +--- src/Memio/Model/Phpdoc/ApiTag.php | 5 +---- src/Memio/Model/Phpdoc/DeprecationTag.php | 9 ++------- src/Memio/Model/Phpdoc/LicensePhpdoc.php | 13 +++---------- src/Memio/Model/Phpdoc/ParameterTag.php | 8 ++------ src/Memio/Model/Phpdoc/ReturnTag.php | 5 +---- src/Memio/Model/Phpdoc/ThrowTag.php | 5 +---- src/Memio/Model/Property.php | 4 +--- 17 files changed, 30 insertions(+), 63 deletions(-) diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 1d77ce4..7ddb923 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -35,12 +35,15 @@ return (new PhpCsFixer\Config()) ->setRules([ '@Symfony' => true, - '@PHP74Migration' => true, - '@PHP74Migration:risky' => true, + '@PHP80Migration' => true, + '@PHP80Migration:risky' => true, // [Symfony] defaults to `camelCase`, we set it to `snake_case` (phpspec style) 'php_unit_method_casing' => ['case' => 'snake_case'], + // [Symfony] defaults to `['arrays']`, we add `arguments` and `parameters` (PHP 8.0) + 'trailing_comma_in_multiline' => ['elements' => ['arrays', 'arguments', 'parameters']], + // [Symfony] defaults to `true`, we set it to `false` for phpspec 'visibility_required' => false, ]) diff --git a/CHANGELOG.md b/CHANGELOG.md index 11fe7b7..cd4f4b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,8 @@ # CHANGELOG -## 4.0.0: PHP 7.4 requirement +## 4.0.0: PHP 8.0 requirement -Dropped support for PHP <7.4 +Dropped support for PHP <8.0 New features: diff --git a/composer.json b/composer.json index 1f1d241..dff7247 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ "Memio\\Model\\": "src/Memio/Model" }}, "require": { - "php": "^7.4 || ^8.0" + "php": "^8.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.19.3", diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 1721f77..365106a 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -3,6 +3,6 @@ includes: parameters: level: 0 - phpVersion: 70400 + phpVersion: 80000 paths: - src/ diff --git a/rector.php b/rector.php index 7bed747..5649d8f 100644 --- a/rector.php +++ b/rector.php @@ -9,7 +9,7 @@ return RectorConfig::configure() ->withCache( '/tmp/rector', - FileCacheStorage::class + FileCacheStorage::class, ) ->withPaths([ __DIR__, @@ -23,7 +23,7 @@ ]) ->withSets([ // —— PHP —————————————————————————————————————————————————————————————— - SetList::PHP_74, + SetList::PHP_80, ]) ->withRules([ ]); diff --git a/spec/Memio/Model/Phpdoc/DescriptionSpec.php b/spec/Memio/Model/Phpdoc/DescriptionSpec.php index 586c6f3..ee7dd00 100644 --- a/spec/Memio/Model/Phpdoc/DescriptionSpec.php +++ b/spec/Memio/Model/Phpdoc/DescriptionSpec.php @@ -50,7 +50,7 @@ function it_can_have_long_description(): void $this->lines->shouldBe(array_merge( [self::SHORT_DESCRIPTION], - $longDescription + $longDescription, )); } } diff --git a/src/Memio/Model/Argument.php b/src/Memio/Model/Argument.php index eab7173..fd72d12 100644 --- a/src/Memio/Model/Argument.php +++ b/src/Memio/Model/Argument.php @@ -19,17 +19,15 @@ class Argument { public Type $type; - public string $name; public ?string $defaultValue = null; public bool $isVariadic = false; /** * @api */ - public function __construct(string $type, string $name) + public function __construct(string $type, public string $name) { $this->type = new Type($type); - $this->name = $name; } /** diff --git a/src/Memio/Model/Constant.php b/src/Memio/Model/Constant.php index fb37601..2ebfa09 100644 --- a/src/Memio/Model/Constant.php +++ b/src/Memio/Model/Constant.php @@ -18,15 +18,12 @@ */ class Constant { - public string $name; - public string $value; - /** * @api */ - public function __construct(string $name, string $value) - { - $this->name = $name; - $this->value = $value; + public function __construct( + public string $name, + public string $value, + ) { } } diff --git a/src/Memio/Model/File.php b/src/Memio/Model/File.php index 5c78537..2b78cfa 100644 --- a/src/Memio/Model/File.php +++ b/src/Memio/Model/File.php @@ -20,7 +20,6 @@ */ class File { - public string $filename; public ?LicensePhpdoc $licensePhpdoc = null; public array $fullyQualifiedNames = []; public ?Structure $structure = null; @@ -28,9 +27,8 @@ class File /** * @api */ - public function __construct(string $filename) + public function __construct(public string $filename) { - $this->filename = $filename; } /** diff --git a/src/Memio/Model/Method.php b/src/Memio/Model/Method.php index e0709a3..23c5809 100644 --- a/src/Memio/Model/Method.php +++ b/src/Memio/Model/Method.php @@ -20,7 +20,6 @@ */ class Method { - public string $name; public ?MethodPhpdoc $methodPhpdoc = null; public bool $isAbstract = false; public bool $isFinal = false; @@ -33,9 +32,8 @@ class Method /** * @api */ - public function __construct(string $name) + public function __construct(public string $name) { - $this->name = $name; } /** diff --git a/src/Memio/Model/Phpdoc/ApiTag.php b/src/Memio/Model/Phpdoc/ApiTag.php index 39ded2f..eb5794e 100644 --- a/src/Memio/Model/Phpdoc/ApiTag.php +++ b/src/Memio/Model/Phpdoc/ApiTag.php @@ -18,13 +18,10 @@ */ class ApiTag { - public ?string $since; - /** * @api */ - public function __construct(?string $since = null) + public function __construct(public ?string $since = null) { - $this->since = $since; } } diff --git a/src/Memio/Model/Phpdoc/DeprecationTag.php b/src/Memio/Model/Phpdoc/DeprecationTag.php index fe0fc7b..a914f9b 100644 --- a/src/Memio/Model/Phpdoc/DeprecationTag.php +++ b/src/Memio/Model/Phpdoc/DeprecationTag.php @@ -18,17 +18,12 @@ */ class DeprecationTag { - public ?string $version; - public ?string $description; - /** * @api */ public function __construct( - ?string $version = null, - ?string $description = null + public ?string $version = null, + public ?string $description = null, ) { - $this->version = $version; - $this->description = $description; } } diff --git a/src/Memio/Model/Phpdoc/LicensePhpdoc.php b/src/Memio/Model/Phpdoc/LicensePhpdoc.php index 13e2858..643401c 100644 --- a/src/Memio/Model/Phpdoc/LicensePhpdoc.php +++ b/src/Memio/Model/Phpdoc/LicensePhpdoc.php @@ -18,20 +18,13 @@ */ class LicensePhpdoc { - public string $projectName; - public string $authorName; - public string $authorEmail; - /** * @api */ public function __construct( - string $projectName, - string $authorName, - string $authorEmail + public string $projectName, + public string $authorName, + public string $authorEmail, ) { - $this->projectName = $projectName; - $this->authorName = $authorName; - $this->authorEmail = $authorEmail; } } diff --git a/src/Memio/Model/Phpdoc/ParameterTag.php b/src/Memio/Model/Phpdoc/ParameterTag.php index a0ad2e5..e9578f6 100644 --- a/src/Memio/Model/Phpdoc/ParameterTag.php +++ b/src/Memio/Model/Phpdoc/ParameterTag.php @@ -21,19 +21,15 @@ class ParameterTag { public Type $type; - public string $name; - public ?string $description; /** * @api */ public function __construct( string $type, - string $name, - ?string $description = null + public string $name, + public ?string $description = null, ) { $this->type = new Type($type); - $this->name = $name; - $this->description = $description; } } diff --git a/src/Memio/Model/Phpdoc/ReturnTag.php b/src/Memio/Model/Phpdoc/ReturnTag.php index d6db11d..c09a6aa 100644 --- a/src/Memio/Model/Phpdoc/ReturnTag.php +++ b/src/Memio/Model/Phpdoc/ReturnTag.php @@ -15,13 +15,10 @@ class ReturnTag { - public string $type; - /** * @api */ - public function __construct(string $type) + public function __construct(public string $type) { - $this->type = $type; } } diff --git a/src/Memio/Model/Phpdoc/ThrowTag.php b/src/Memio/Model/Phpdoc/ThrowTag.php index 6faa0de..c9136f9 100644 --- a/src/Memio/Model/Phpdoc/ThrowTag.php +++ b/src/Memio/Model/Phpdoc/ThrowTag.php @@ -15,13 +15,10 @@ class ThrowTag { - public string $exception; - /** * @api */ - public function __construct(string $exception) + public function __construct(public string $exception) { - $this->exception = $exception; } } diff --git a/src/Memio/Model/Property.php b/src/Memio/Model/Property.php index fd48caf..995cf12 100644 --- a/src/Memio/Model/Property.php +++ b/src/Memio/Model/Property.php @@ -20,7 +20,6 @@ */ class Property { - public string $name; public ?Type $type = null; public ?PropertyPhpdoc $propertyPhpdoc = null; public bool $isStatic = false; @@ -30,9 +29,8 @@ class Property /** * @api */ - public function __construct(string $name) + public function __construct(public string $name) { - $this->name = $name; } /** From 3efc9a8be54fd14070a5133dd2d7b2e55c167a19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Faugeron?= Date: Fri, 13 Feb 2026 07:18:36 +0000 Subject: [PATCH 12/18] feat: added Attribute model and attributes support --- spec/Memio/Model/ArgumentSpec.php | 8 ++++++ spec/Memio/Model/AttributeSpec.php | 39 +++++++++++++++++++++++++++++ spec/Memio/Model/ConstantSpec.php | 8 ++++++ spec/Memio/Model/ContractSpec.php | 8 ++++++ spec/Memio/Model/MethodSpec.php | 8 ++++++ spec/Memio/Model/ObjektSpec.php | 8 ++++++ spec/Memio/Model/PropertySpec.php | 8 ++++++ src/Memio/Model/Argument.php | 11 ++++++++ src/Memio/Model/Attribute.php | 40 ++++++++++++++++++++++++++++++ src/Memio/Model/Constant.php | 12 +++++++++ src/Memio/Model/Contract.php | 11 ++++++++ src/Memio/Model/Method.php | 11 ++++++++ src/Memio/Model/Objekt.php | 11 ++++++++ src/Memio/Model/Property.php | 11 ++++++++ 14 files changed, 194 insertions(+) create mode 100644 spec/Memio/Model/AttributeSpec.php create mode 100644 src/Memio/Model/Attribute.php diff --git a/spec/Memio/Model/ArgumentSpec.php b/spec/Memio/Model/ArgumentSpec.php index 10717a0..538ee79 100644 --- a/spec/Memio/Model/ArgumentSpec.php +++ b/spec/Memio/Model/ArgumentSpec.php @@ -13,6 +13,7 @@ namespace spec\Memio\Model; +use Memio\Model\Attribute; use PhpSpec\ObjectBehavior; class ArgumentSpec extends ObjectBehavior @@ -53,4 +54,11 @@ function it_can_be_variadic(): void $this->removeVariadic(); $this->isVariadic()->shouldBe(false); } + + function it_can_have_attributes(Attribute $attribute): void + { + $this->attributes->shouldBe([]); + $this->addAttribute($attribute); + $this->attributes->shouldBe([$attribute]); + } } diff --git a/spec/Memio/Model/AttributeSpec.php b/spec/Memio/Model/AttributeSpec.php new file mode 100644 index 0000000..e6adead --- /dev/null +++ b/spec/Memio/Model/AttributeSpec.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace spec\Memio\Model; + +use PhpSpec\ObjectBehavior; + +class AttributeSpec extends ObjectBehavior +{ + const NAME = 'Route'; + + function let(): void + { + $this->beConstructedWith(self::NAME); + } + + function it_has_a_name(): void + { + $this->name->shouldBe(self::NAME); + } + + function it_can_have_arguments(): void + { + $this->arguments->shouldBe(null); + + $this->setArguments("'/api'"); + $this->arguments->shouldBe("'/api'"); + } +} diff --git a/spec/Memio/Model/ConstantSpec.php b/spec/Memio/Model/ConstantSpec.php index e5097f7..676395d 100644 --- a/spec/Memio/Model/ConstantSpec.php +++ b/spec/Memio/Model/ConstantSpec.php @@ -13,6 +13,7 @@ namespace spec\Memio\Model; +use Memio\Model\Attribute; use PhpSpec\ObjectBehavior; class ConstantSpec extends ObjectBehavior @@ -34,4 +35,11 @@ function it_has_a_value(): void { $this->value->shouldBe(self::VALUE); } + + function it_can_have_attributes(Attribute $attribute): void + { + $this->attributes->shouldBe([]); + $this->addAttribute($attribute); + $this->attributes->shouldBe([$attribute]); + } } diff --git a/spec/Memio/Model/ContractSpec.php b/spec/Memio/Model/ContractSpec.php index 5c46418..9d62e3d 100644 --- a/spec/Memio/Model/ContractSpec.php +++ b/spec/Memio/Model/ContractSpec.php @@ -13,6 +13,7 @@ namespace spec\Memio\Model; +use Memio\Model\Attribute; use Memio\Model\Constant; use Memio\Model\Contract; use Memio\Model\Method; @@ -77,4 +78,11 @@ function it_can_have_methods(Method $method): void $this->addMethod($method); $this->methods->shouldBe([$method]); } + + function it_can_have_attributes(Attribute $attribute): void + { + $this->attributes->shouldBe([]); + $this->addAttribute($attribute); + $this->attributes->shouldBe([$attribute]); + } } diff --git a/spec/Memio/Model/MethodSpec.php b/spec/Memio/Model/MethodSpec.php index 8b2c384..cda4803 100644 --- a/spec/Memio/Model/MethodSpec.php +++ b/spec/Memio/Model/MethodSpec.php @@ -14,6 +14,7 @@ namespace spec\Memio\Model; use Memio\Model\Argument; +use Memio\Model\Attribute; use Memio\Model\Phpdoc\MethodPhpdoc; use PhpSpec\ObjectBehavior; @@ -110,4 +111,11 @@ function it_can_have_a_body(): void $this->setBody($body); $this->body->shouldBe($body); } + + function it_can_have_attributes(Attribute $attribute): void + { + $this->attributes->shouldBe([]); + $this->addAttribute($attribute); + $this->attributes->shouldBe([$attribute]); + } } diff --git a/spec/Memio/Model/ObjektSpec.php b/spec/Memio/Model/ObjektSpec.php index b0de5a2..a740d08 100644 --- a/spec/Memio/Model/ObjektSpec.php +++ b/spec/Memio/Model/ObjektSpec.php @@ -13,6 +13,7 @@ namespace spec\Memio\Model; +use Memio\Model\Attribute; use Memio\Model\Constant; use Memio\Model\Contract; use Memio\Model\Method; @@ -118,4 +119,11 @@ function it_can_have_methods(Method $method): void $this->addMethod($method); $this->methods->shouldBe([$method]); } + + function it_can_have_attributes(Attribute $attribute): void + { + $this->attributes->shouldBe([]); + $this->addAttribute($attribute); + $this->attributes->shouldBe([$attribute]); + } } diff --git a/spec/Memio/Model/PropertySpec.php b/spec/Memio/Model/PropertySpec.php index 301c4ab..9ac696e 100644 --- a/spec/Memio/Model/PropertySpec.php +++ b/spec/Memio/Model/PropertySpec.php @@ -13,6 +13,7 @@ namespace spec\Memio\Model; +use Memio\Model\Attribute; use Memio\Model\Phpdoc\PropertyPhpdoc; use PhpSpec\ObjectBehavior; @@ -79,4 +80,11 @@ function it_can_have_a_default_value(): void $this->setDefaultValue('null'); $this->defaultValue->shouldBe('null'); } + + function it_can_have_attributes(Attribute $attribute): void + { + $this->attributes->shouldBe([]); + $this->addAttribute($attribute); + $this->attributes->shouldBe([$attribute]); + } } diff --git a/src/Memio/Model/Argument.php b/src/Memio/Model/Argument.php index fd72d12..a91f510 100644 --- a/src/Memio/Model/Argument.php +++ b/src/Memio/Model/Argument.php @@ -18,6 +18,7 @@ */ class Argument { + public array $attributes = []; public Type $type; public ?string $defaultValue = null; public bool $isVariadic = false; @@ -30,6 +31,16 @@ public function __construct(string $type, public string $name) $this->type = new Type($type); } + /** + * @api + */ + public function addAttribute(Attribute $attribute): self + { + $this->attributes[] = $attribute; + + return $this; + } + /** * @api */ diff --git a/src/Memio/Model/Attribute.php b/src/Memio/Model/Attribute.php new file mode 100644 index 0000000..42d5623 --- /dev/null +++ b/src/Memio/Model/Attribute.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Memio\Model; + +/** + * @api + */ +class Attribute +{ + public ?string $arguments = null; + + /** + * @api + */ + public function __construct( + public string $name, + ) { + } + + /** + * @api + */ + public function setArguments(string $arguments): self + { + $this->arguments = $arguments; + + return $this; + } +} diff --git a/src/Memio/Model/Constant.php b/src/Memio/Model/Constant.php index 2ebfa09..31560c4 100644 --- a/src/Memio/Model/Constant.php +++ b/src/Memio/Model/Constant.php @@ -18,6 +18,8 @@ */ class Constant { + public array $attributes = []; + /** * @api */ @@ -26,4 +28,14 @@ public function __construct( public string $value, ) { } + + /** + * @api + */ + public function addAttribute(Attribute $attribute): self + { + $this->attributes[] = $attribute; + + return $this; + } } diff --git a/src/Memio/Model/Contract.php b/src/Memio/Model/Contract.php index 97520a1..e5b7fbc 100644 --- a/src/Memio/Model/Contract.php +++ b/src/Memio/Model/Contract.php @@ -24,6 +24,7 @@ class Contract implements Structure { public FullyQualifiedName $fullyQualifiedName; public ?StructurePhpdoc $structurePhpdoc = null; + public array $attributes = []; public array $contracts = []; public array $constants = []; public array $methods = []; @@ -61,6 +62,16 @@ public function setPhpdoc(StructurePhpdoc $structurePhpdoc): self return $this; } + /** + * @api + */ + public function addAttribute(Attribute $attribute): self + { + $this->attributes[] = $attribute; + + return $this; + } + /** * @api */ diff --git a/src/Memio/Model/Method.php b/src/Memio/Model/Method.php index 23c5809..0be7068 100644 --- a/src/Memio/Model/Method.php +++ b/src/Memio/Model/Method.php @@ -20,6 +20,7 @@ */ class Method { + public array $attributes = []; public ?MethodPhpdoc $methodPhpdoc = null; public bool $isAbstract = false; public bool $isFinal = false; @@ -36,6 +37,16 @@ public function __construct(public string $name) { } + /** + * @api + */ + public function addAttribute(Attribute $attribute): self + { + $this->attributes[] = $attribute; + + return $this; + } + /** * @api */ diff --git a/src/Memio/Model/Objekt.php b/src/Memio/Model/Objekt.php index e2259a9..b7d6c9e 100644 --- a/src/Memio/Model/Objekt.php +++ b/src/Memio/Model/Objekt.php @@ -28,6 +28,7 @@ class Objekt implements Structure public bool $isFinal = false; public ?Objekt $parent = null; public array $contracts = []; + public array $attributes = []; public array $constants = []; public array $properties = []; public array $methods = []; @@ -130,6 +131,16 @@ public function removeParent(): self return $this; } + /** + * @api + */ + public function addAttribute(Attribute $attribute): self + { + $this->attributes[] = $attribute; + + return $this; + } + /** * @api */ diff --git a/src/Memio/Model/Property.php b/src/Memio/Model/Property.php index 995cf12..c602508 100644 --- a/src/Memio/Model/Property.php +++ b/src/Memio/Model/Property.php @@ -20,6 +20,7 @@ */ class Property { + public array $attributes = []; public ?Type $type = null; public ?PropertyPhpdoc $propertyPhpdoc = null; public bool $isStatic = false; @@ -33,6 +34,16 @@ public function __construct(public string $name) { } + /** + * @api + */ + public function addAttribute(Attribute $attribute): self + { + $this->attributes[] = $attribute; + + return $this; + } + /** * @api */ From c5c2a788eb7b06b92fb550a39dd81ec17dd34a07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Faugeron?= Date: Fri, 13 Feb 2026 07:19:49 +0000 Subject: [PATCH 13/18] feat: added union types support --- spec/Memio/Model/TypeSpec.php | 36 +++++++++++++++++++++++++++++++++++ src/Memio/Model/Type.php | 21 ++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/spec/Memio/Model/TypeSpec.php b/spec/Memio/Model/TypeSpec.php index b0641cb..297185c 100644 --- a/spec/Memio/Model/TypeSpec.php +++ b/spec/Memio/Model/TypeSpec.php @@ -245,4 +245,40 @@ function it_normalizes_nullable_names(): void $this->isObject()->shouldBe(false); $this->isNullable()->shouldBe(true); } + + function it_can_be_a_union_type(): void + { + $this->beConstructedWith('string|int'); + + $this->getName()->shouldBe('string|int'); + $this->isUnionType->shouldBe(true); + $this->hasTypeHint()->shouldBe(true); + $this->types->shouldHaveCount(2); + } + + function it_can_be_a_nullable_union_type(): void + { + $this->beConstructedWith('string|null'); + + $this->getName()->shouldBe('string|null'); + $this->isUnionType->shouldBe(true); + $this->isNullable()->shouldBe(true); + } + + function it_normalizes_union_type_names(): void + { + $this->beConstructedWith('boolean|integer'); + + $this->getName()->shouldBe('bool|int'); + $this->isUnionType->shouldBe(true); + } + + function it_can_be_a_union_type_with_object(): void + { + $this->beConstructedWith('DateTime|string'); + + $this->getName()->shouldBe('DateTime|string'); + $this->isUnionType->shouldBe(true); + $this->types[0]->isObject->shouldBe(true); + } } diff --git a/src/Memio/Model/Type.php b/src/Memio/Model/Type.php index 20c848f..24e2576 100644 --- a/src/Memio/Model/Type.php +++ b/src/Memio/Model/Type.php @@ -48,6 +48,9 @@ class Type public bool $isObject; public bool $hasTypeHint; public bool $isNullable; + public bool $isUnionType = false; + /** @var Type[] */ + public array $types = []; /** * @api @@ -58,6 +61,24 @@ public function __construct(string $name) if ($this->isNullable) { $name = substr($name, 1); } + if (str_contains($name, '|')) { + $this->isUnionType = true; + $this->hasTypeHint = true; + $this->isObject = false; + $parts = explode('|', $name); + $normalizedParts = []; + foreach ($parts as $part) { + $type = new self($part); + $this->types[] = $type; + $normalizedParts[] = $type->name; + if ('null' === $type->name) { + $this->isNullable = true; + } + } + $this->name = implode('|', $normalizedParts); + + return; + } if (isset(self::NORMALIZATIONS[$name])) { $name = self::NORMALIZATIONS[$name]; } From be604a0ccfbfbac017293f2c6f9c0af517bebfe8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Faugeron?= Date: Fri, 13 Feb 2026 07:20:03 +0000 Subject: [PATCH 14/18] feat: added mixed type hint support --- spec/Memio/Model/TypeSpec.php | 1 + src/Memio/Model/Type.php | 1 + 2 files changed, 2 insertions(+) diff --git a/spec/Memio/Model/TypeSpec.php b/spec/Memio/Model/TypeSpec.php index 297185c..ef09e6e 100644 --- a/spec/Memio/Model/TypeSpec.php +++ b/spec/Memio/Model/TypeSpec.php @@ -205,6 +205,7 @@ function it_can_be_unknown(): void $this->getName()->shouldBe('mixed'); $this->isObject()->shouldBe(false); + $this->hasTypeHint()->shouldBe(true); } function it_can_be_a_nullable_object(): void diff --git a/src/Memio/Model/Type.php b/src/Memio/Model/Type.php index 24e2576..17416cd 100644 --- a/src/Memio/Model/Type.php +++ b/src/Memio/Model/Type.php @@ -42,6 +42,7 @@ class Type 'float', 'int', 'string', + 'mixed', ]; public string $name; From bc36a465347af187c2b73cdc7c0877e002812876 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Faugeron?= Date: Fri, 13 Feb 2026 07:20:23 +0000 Subject: [PATCH 15/18] chore: updated docs for 4.0.0 --- CHANGELOG.md | 4 ++++ README.md | 3 +-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd4f4b3..03b5521 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ Dropped support for PHP <8.0 New features: +* added `Attribute` model (PHP 8.0 attributes) +* added attributes support to `Objekt`, `Contract`, `Method`, `Property`, `Argument` and `Constant` +* added union type support in `Type` (e.g. `string|int`, `DateTime|null`) +* added `mixed` type hint support in `Type` * added support for class property types * added support for nullable typehints diff --git a/README.md b/README.md index 0472105..a3da051 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ method arguments and even PHPdoc) by constructing "Model" objects. Install it using [Composer](https://getcomposer.org/download): - composer require memio/model:^3.0 + composer require memio/model:^4.0 ## Example @@ -113,4 +113,3 @@ And finally some meta documentation: * extract `Import` (use statement) from `FullyQualifiedName` * get rid of `FullyQualifiedName` * support more PHPdoc stuff -* support annotations From 3424be7ae68f64412c208f291f1ff56a88431c30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Faugeron?= Date: Fri, 13 Feb 2026 07:35:49 +0000 Subject: [PATCH 16/18] chore: code review fixes for 4.0.0 * removed redundant version_compare PHP 7.0 tests in TypeSpec * added addAttribute/removeAttributes to Structure interface * added public visibility to HAS_TYPE_HINT constant in Type * added removeAttributes() to Argument, Constant, Contract, Method, Objekt, Property _AI Disclosure_: used Claude Code (v2.1.39, Opus 4.6), to help with the chores. --- spec/Memio/Model/ArgumentSpec.php | 2 ++ spec/Memio/Model/ConstantSpec.php | 2 ++ spec/Memio/Model/ContractSpec.php | 2 ++ spec/Memio/Model/MethodSpec.php | 2 ++ spec/Memio/Model/ObjektSpec.php | 2 ++ spec/Memio/Model/PropertySpec.php | 2 ++ spec/Memio/Model/TypeSpec.php | 28 ---------------------------- src/Memio/Model/Argument.php | 8 ++++++++ src/Memio/Model/Constant.php | 8 ++++++++ src/Memio/Model/Contract.php | 8 ++++++++ src/Memio/Model/Method.php | 8 ++++++++ src/Memio/Model/Objekt.php | 8 ++++++++ src/Memio/Model/Property.php | 8 ++++++++ src/Memio/Model/Structure.php | 10 ++++++++++ src/Memio/Model/Type.php | 2 +- 15 files changed, 71 insertions(+), 29 deletions(-) diff --git a/spec/Memio/Model/ArgumentSpec.php b/spec/Memio/Model/ArgumentSpec.php index 538ee79..f771d7b 100644 --- a/spec/Memio/Model/ArgumentSpec.php +++ b/spec/Memio/Model/ArgumentSpec.php @@ -60,5 +60,7 @@ function it_can_have_attributes(Attribute $attribute): void $this->attributes->shouldBe([]); $this->addAttribute($attribute); $this->attributes->shouldBe([$attribute]); + $this->removeAttributes(); + $this->attributes->shouldBe([]); } } diff --git a/spec/Memio/Model/ConstantSpec.php b/spec/Memio/Model/ConstantSpec.php index 676395d..d03f2d0 100644 --- a/spec/Memio/Model/ConstantSpec.php +++ b/spec/Memio/Model/ConstantSpec.php @@ -41,5 +41,7 @@ function it_can_have_attributes(Attribute $attribute): void $this->attributes->shouldBe([]); $this->addAttribute($attribute); $this->attributes->shouldBe([$attribute]); + $this->removeAttributes(); + $this->attributes->shouldBe([]); } } diff --git a/spec/Memio/Model/ContractSpec.php b/spec/Memio/Model/ContractSpec.php index 9d62e3d..277549a 100644 --- a/spec/Memio/Model/ContractSpec.php +++ b/spec/Memio/Model/ContractSpec.php @@ -84,5 +84,7 @@ function it_can_have_attributes(Attribute $attribute): void $this->attributes->shouldBe([]); $this->addAttribute($attribute); $this->attributes->shouldBe([$attribute]); + $this->removeAttributes(); + $this->attributes->shouldBe([]); } } diff --git a/spec/Memio/Model/MethodSpec.php b/spec/Memio/Model/MethodSpec.php index cda4803..a60e7a8 100644 --- a/spec/Memio/Model/MethodSpec.php +++ b/spec/Memio/Model/MethodSpec.php @@ -117,5 +117,7 @@ function it_can_have_attributes(Attribute $attribute): void $this->attributes->shouldBe([]); $this->addAttribute($attribute); $this->attributes->shouldBe([$attribute]); + $this->removeAttributes(); + $this->attributes->shouldBe([]); } } diff --git a/spec/Memio/Model/ObjektSpec.php b/spec/Memio/Model/ObjektSpec.php index a740d08..17aa5c5 100644 --- a/spec/Memio/Model/ObjektSpec.php +++ b/spec/Memio/Model/ObjektSpec.php @@ -125,5 +125,7 @@ function it_can_have_attributes(Attribute $attribute): void $this->attributes->shouldBe([]); $this->addAttribute($attribute); $this->attributes->shouldBe([$attribute]); + $this->removeAttributes(); + $this->attributes->shouldBe([]); } } diff --git a/spec/Memio/Model/PropertySpec.php b/spec/Memio/Model/PropertySpec.php index 9ac696e..9763752 100644 --- a/spec/Memio/Model/PropertySpec.php +++ b/spec/Memio/Model/PropertySpec.php @@ -86,5 +86,7 @@ function it_can_have_attributes(Attribute $attribute): void $this->attributes->shouldBe([]); $this->addAttribute($attribute); $this->attributes->shouldBe([$attribute]); + $this->removeAttributes(); + $this->attributes->shouldBe([]); } } diff --git a/spec/Memio/Model/TypeSpec.php b/spec/Memio/Model/TypeSpec.php index ef09e6e..4fa858c 100644 --- a/spec/Memio/Model/TypeSpec.php +++ b/spec/Memio/Model/TypeSpec.php @@ -75,34 +75,6 @@ function it_can_have_a_type_hint_if_it_is_a_boolean(): void $this->hasTypeHint()->shouldBe(true); } - function it_can_have_a_type_hint_if_it_is_a_string_from_php_7_0(): void - { - $this->beConstructedWith('string'); - - $this->hasTypeHint()->shouldBe(version_compare(PHP_VERSION, '7.0.0') >= 0); - } - - function it_can_have_a_type_hint_if_it_is_an_integer_from_php_7_0(): void - { - $this->beConstructedWith('int'); - - $this->hasTypeHint()->shouldBe(version_compare(PHP_VERSION, '7.0.0') >= 0); - } - - function it_can_have_a_type_hint_if_it_is_a_float_from_php_7_0(): void - { - $this->beConstructedWith('float'); - - $this->hasTypeHint()->shouldBe(version_compare(PHP_VERSION, '7.0.0') >= 0); - } - - function it_can_have_a_type_hint_if_it_is_a_boolean_from_php_7_0(): void - { - $this->beConstructedWith('bool'); - - $this->hasTypeHint()->shouldBe(version_compare(PHP_VERSION, '7.0.0') >= 0); - } - function it_can_be_an_array(): void { $this->beConstructedWith('array'); diff --git a/src/Memio/Model/Argument.php b/src/Memio/Model/Argument.php index a91f510..6face99 100644 --- a/src/Memio/Model/Argument.php +++ b/src/Memio/Model/Argument.php @@ -41,6 +41,14 @@ public function addAttribute(Attribute $attribute): self return $this; } + /** + * @api + */ + public function removeAttributes(): void + { + $this->attributes = []; + } + /** * @api */ diff --git a/src/Memio/Model/Constant.php b/src/Memio/Model/Constant.php index 31560c4..c612504 100644 --- a/src/Memio/Model/Constant.php +++ b/src/Memio/Model/Constant.php @@ -38,4 +38,12 @@ public function addAttribute(Attribute $attribute): self return $this; } + + /** + * @api + */ + public function removeAttributes(): void + { + $this->attributes = []; + } } diff --git a/src/Memio/Model/Contract.php b/src/Memio/Model/Contract.php index e5b7fbc..1cb4d4f 100644 --- a/src/Memio/Model/Contract.php +++ b/src/Memio/Model/Contract.php @@ -72,6 +72,14 @@ public function addAttribute(Attribute $attribute): self return $this; } + /** + * @api + */ + public function removeAttributes(): void + { + $this->attributes = []; + } + /** * @api */ diff --git a/src/Memio/Model/Method.php b/src/Memio/Model/Method.php index 0be7068..87d9252 100644 --- a/src/Memio/Model/Method.php +++ b/src/Memio/Model/Method.php @@ -47,6 +47,14 @@ public function addAttribute(Attribute $attribute): self return $this; } + /** + * @api + */ + public function removeAttributes(): void + { + $this->attributes = []; + } + /** * @api */ diff --git a/src/Memio/Model/Objekt.php b/src/Memio/Model/Objekt.php index b7d6c9e..86c5077 100644 --- a/src/Memio/Model/Objekt.php +++ b/src/Memio/Model/Objekt.php @@ -141,6 +141,14 @@ public function addAttribute(Attribute $attribute): self return $this; } + /** + * @api + */ + public function removeAttributes(): void + { + $this->attributes = []; + } + /** * @api */ diff --git a/src/Memio/Model/Property.php b/src/Memio/Model/Property.php index c602508..46acc95 100644 --- a/src/Memio/Model/Property.php +++ b/src/Memio/Model/Property.php @@ -44,6 +44,14 @@ public function addAttribute(Attribute $attribute): self return $this; } + /** + * @api + */ + public function removeAttributes(): void + { + $this->attributes = []; + } + /** * @api */ diff --git a/src/Memio/Model/Structure.php b/src/Memio/Model/Structure.php index a7f9d81..fa53f1e 100644 --- a/src/Memio/Model/Structure.php +++ b/src/Memio/Model/Structure.php @@ -32,4 +32,14 @@ public function getName(): string; * @api */ public function setPhpdoc(StructurePhpdoc $structurePhpdoc); + + /** + * @api + */ + public function addAttribute(Attribute $attribute); + + /** + * @api + */ + public function removeAttributes(): void; } diff --git a/src/Memio/Model/Type.php b/src/Memio/Model/Type.php index 17416cd..cf7b6fe 100644 --- a/src/Memio/Model/Type.php +++ b/src/Memio/Model/Type.php @@ -35,7 +35,7 @@ class Type 'null', 'mixed', ]; - const HAS_TYPE_HINT = [ + public const HAS_TYPE_HINT = [ 'array', 'callable', 'bool', From 4649a8d070f0ee031a38c63017f78db2af258a5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Faugeron?= Date: Fri, 13 Feb 2026 07:46:44 +0000 Subject: [PATCH 17/18] feat: added constructor property promotion support --- CHANGELOG.md | 1 + spec/Memio/Model/ArgumentSpec.php | 17 +++++++++++++ src/Memio/Model/Argument.php | 41 +++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 03b5521..49024b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ New features: * added union type support in `Type` (e.g. `string|int`, `DateTime|null`) * added `mixed` type hint support in `Type` * added support for class property types +* added constructor property promotion support (visibility on `Argument`) * added support for nullable typehints ## 3.0.2: Dockerised dev environment diff --git a/spec/Memio/Model/ArgumentSpec.php b/spec/Memio/Model/ArgumentSpec.php index f771d7b..5476054 100644 --- a/spec/Memio/Model/ArgumentSpec.php +++ b/spec/Memio/Model/ArgumentSpec.php @@ -63,4 +63,21 @@ function it_can_have_attributes(Attribute $attribute): void $this->removeAttributes(); $this->attributes->shouldBe([]); } + + function it_can_have_visibility(): void + { + $this->visibility->shouldBe(''); + + $this->makePublic(); + $this->visibility->shouldBe('public'); + + $this->makeProtected(); + $this->visibility->shouldBe('protected'); + + $this->makePrivate(); + $this->visibility->shouldBe('private'); + + $this->removeVisibility(); + $this->visibility->shouldBe(''); + } } diff --git a/src/Memio/Model/Argument.php b/src/Memio/Model/Argument.php index 6face99..3622a8f 100644 --- a/src/Memio/Model/Argument.php +++ b/src/Memio/Model/Argument.php @@ -19,6 +19,7 @@ class Argument { public array $attributes = []; + public string $visibility = ''; public Type $type; public ?string $defaultValue = null; public bool $isVariadic = false; @@ -96,4 +97,44 @@ public function removeVariadic(): self return $this; } + + /** + * @api + */ + public function makePublic(): self + { + $this->visibility = 'public'; + + return $this; + } + + /** + * @api + */ + public function makeProtected(): self + { + $this->visibility = 'protected'; + + return $this; + } + + /** + * @api + */ + public function makePrivate(): self + { + $this->visibility = 'private'; + + return $this; + } + + /** + * @api + */ + public function removeVisibility(): self + { + $this->visibility = ''; + + return $this; + } } From ba8050528196210d7662ce4803d12f9861d3b23e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Faugeron?= Date: Fri, 13 Feb 2026 08:15:41 +0000 Subject: [PATCH 18/18] chore: updated docs for 4.0.0 --- CHANGELOG.md | 8 ++--- CONTRIBUTING.md | 6 ++-- README.md | 77 +++++++++++++++++++++++++------------------------ 3 files changed, 46 insertions(+), 45 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 49024b1..1ca5ab2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,9 +18,9 @@ New features: * setup Github Actions * changed tooling from scripts to Makefile -* installed phpstan as a dev depdendency -* installed swiss-knife as a dev depdendency -* installed rector as a dev depdendency +* installed phpstan as a dev dependency +* installed swiss-knife as a dev dependency +* installed rector as a dev dependency * upgraded PHP CS fixer to v2.19.3 * dockerized for local development @@ -55,7 +55,7 @@ Normalization from float to double, thanks to @ItsKelsBoys Added support for PHP 7.2, thanks to @roukmoute -BC break: Object has be renamed to Objekt, has it is a reserved keyword. +BC break: Object has been renamed to Objekt, has it is a reserved keyword. ## 2.0.0: PHP 7 and Return type hints diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f400a0c..ab266ae 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -30,7 +30,7 @@ make lib-init ## Standard code -Use [PHP CS fixer](http://cs.sensiolabs.org/) to make your code compliant with +Use [PHP CS Fixer](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer) to make your code compliant with Memio's coding standards: ```console @@ -87,7 +87,7 @@ To keep your fork up-to-date, you should track the upstream (original) one using the following command: ```console -$ git remote add upstream https://github.com/memio/model.git +git remote add upstream https://github.com/memio/model.git ``` Then get the upstream changes: @@ -103,7 +103,7 @@ git rebase main Finally, publish your changes: ```console -$ git push -f origin +git push -f origin ``` Your pull request will be automatically updated. diff --git a/README.md b/README.md index a3da051..0a9b60e 100644 --- a/README.md +++ b/README.md @@ -10,17 +10,21 @@ method arguments and even PHPdoc) by constructing "Model" objects. Install it using [Composer](https://getcomposer.org/download): - composer require memio/model:^4.0 +```console +composer require memio/model:^4.0 +``` ## Example -Let's say we want to describe the following method: +Let's say we want to describe the following constructor: ```php - /** - * @api - */ - public function doSomething(ValueObject $valueObject, int $type = self::TYPE_ONE, bool $option = true); + public function __construct( + private ValueObject $valueObject, + private string|int $type = self::TYPE_ONE, + private ?bool $option = true, + ) { + } ``` In order to do so, we'd need to write the following: @@ -32,56 +36,53 @@ require __DIR__.'/vendor/autoload.php'; use Memio\Model\Argument; use Memio\Model\Method; -use Memio\Model\Phpdoc\ApiTag; -use Memio\Model\Phpdoc\MethodPhpdoc; -use Memio\Model\Phpdoc\ParameterTag; - -$method = (new Method('doSomething')) - ->setPhpdoc((new MethodPhpdoc()) - ->addParameterTag(new ParameterTag('Vendor\Project\ValueObject', 'valueObject')) - ->addParameterTag(new ParameterTag('int', 'type')) - ->addParameterTag(new ParameterTag('bool', 'option')) - ->addApiTag(new ApiTag()) +$method = (new Method('__construct')) + ->addArgument((new Argument('Vendor\Project\ValueObject', 'valueObject')) + ->makePrivate() ) - ->addArgument(new Argument('Vendor\Project\ValueObject', 'valueObject')) - ->addArgument((new Argument('int', 'type')) + ->addArgument((new Argument('string|int', 'type')) + ->makePrivate() ->setDefaultValue('self::TYPE_ONE') ) - ->addArgument((new Argument('bool', 'option')) + ->addArgument((new Argument('?bool', 'option')) + ->makePrivate() ->setDefaultValue('true') ) ; ``` +This example showcases constructor property promotion, union types and nullable types. + Usually models aren't described manually like this, they would be built dynamically: ```php -// Let's say we've received the following two parameters: -$methodName = 'doSomething'; -$arguments = [new \Vendor\Project\ValueObject(), ValueObject::TYPE_ONE, true]; - -$method = new Method($methodName); -$phpdoc = (new MethodPhpdoc())->setApiTag(new ApiTag()); -$index = 1; -foreach ($arguments as $rawArgument) { - $type = is_object($rawArgument) ? get_class($argument) : gettype($rawArgument); - $name = 'argument'.$index++; - $argument = new Argument($type, $name); - +// Let's say we've received the following parameters: +$parameters = [ + ['type' => 'Vendor\Project\ValueObject', 'name' => 'valueObject'], + ['type' => 'string|int', 'name' => 'type', 'default' => 'self::TYPE_ONE'], + ['type' => '?bool', 'name' => 'option', 'default' => 'true'], +]; + +$method = new Method('__construct'); +foreach ($parameters as $parameter) { + $argument = (new Argument($parameter['type'], $parameter['name'])) + ->makePrivate() + ; + if (isset($parameter['default'])) { + $argument->setDefaultValue($parameter['default']); + } $method->addArgument($argument); - $phpdoc->addParameterTag(new ParameterTag($type, $name)); } -$method->setPhpdoc($phpdoc); ``` We can build dynamically the models using a configuration file, user input, existing -source code... Possibilities are endless! +source code, etc. Possibilities are endless! -Once built these models can be further tweaked, and converted to another format: -an array, source code, etc... Again, the possibilities are endless! +Once built, these models can be further tweaked and converted to another format: +an array, source code, etc. -Have a look at [the main respository](http://github.com/memio/memio) to discover the full power of Medio. +Have a look at [the main repository](http://github.com/memio/memio) to discover the full power of Memio. ## Want to know more? @@ -98,7 +99,7 @@ make phpspec arg='--format pretty' # Run the specifications You can see the current and past versions using one of the following: * the `git tag` command -* the [releases page on Github](https://github.com/memio/memio/releases) +* the [releases page on Github](https://github.com/memio/model/releases) * the file listing the [changes between versions](CHANGELOG.md) And finally some meta documentation: