Download the PHP package dave-liddament/php-language-extensions without Composer
On this page you can find all versions of the php package dave-liddament/php-language-extensions. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download dave-liddament/php-language-extensions
More information about dave-liddament/php-language-extensions
Files in dave-liddament/php-language-extensions
Package php-language-extensions
Short Description Attributes for extending the PHP language, using static analysis to enforce new language constructs
License MIT
Informations about the package php-language-extensions
PHP Language Extensions (currently in BETA)
This library provides attributes that are used by static analysers to enforce new language features. The intention, at least initially, is that these extra language features are enforced by static analysis tools (such as Psalm, PHPStan and, ideally, PhpStorm) and NOT at runtime.
Language feature added:
- Friend
- MustUseResult
- NamespaceVisibility
- InjectableVersion
- Override
- RestrictTraitTo
- Sealed
- TestTag
Contents
- Installation
- PHPStan
- Psalm
-
New Language Features
- Friend
- MustUseResult
- NamespaceVisibility
- InjectableVersion
- Override
- RestrictTraitTo
- Sealed
- TestTag
- Deprecated
- NamespaceVisibility
- Further examples
- Contributing
Installation
To make the attributes available for your codebase use:
NOTE: This only installs the attributes. A static analysis tool is used to enforce these language extensions. Use one of these:
PHPStan
If you're using PHPStan then use this extension to enforce the rules.
Psalm
Coming soon.
New language features
Friend
A method or class can supply via a #[Friend]
attribute a list of classes. Only these classes can call the method.
This is loosely based on the C++ friend feature.
In the example below the Person::__construct
method can only be called from PersonBuilder
:
NOTES:
- Multiple classes can be specified. E.g.
#[Friend(Foo::class, Bar::class)]
-
A class can have a
#[Friend]
attribute, classes listed here are applied to every method. -
The
#[Friend]
attribute is additive. If a class and a method have the#[Friend]
the method can be called from any of the classes listed. E.g. - This is currently limited to method calls (including
__construct
).
MustUseResult
A #[MustUseResult]
attribute can be used on methods. This enforces the result from the method call must be used.
E.g. if you have a class like this:
You might misuse the add
method in this way:
But this would be OK:
NamespaceVisibility
The #[NamespaceVisibility]
attribute acts as extra visibility modifier like public
, protected
and private
.
By default, the #[NamespaceVisibility]
attribute limits the visibility of a class or method to only being accessible from in the same namespace, or sub namespace.
Example applying #[NamespaceVisibility]
to the Telephone::ring
method:
The #[NamespaceVisibility]
attribute has 2 optional arguments:
excludeSubNamespaces option
This is a boolean value. Its default value is false. If set to true then calls to methods from sub namespaces are not allowed. E.g.
namespace option
This is a string or null value. Its default value is null. If it is set, then this is the namespace that you are allowed to call the method on.
In the example below you can only call Telephone::ring
from the Bar
namespace.
NamespaceVisibility on classes
If a class was the #[NamespaceVisibility]
Attribute, then all its public methods are treated as Namespace visibility.
E.g.
If both the class and one of the class's methods has a #[NamespaceVisibility]
attribute, then the method's attribute
takes precedence.
NOTES:
- If adding the
#[NamespaceVisibility]
to a method, this method MUST have public visibility. - This is currently limited to method calls (including
__construct
).
InjectableVersion
The #[InjectableVersion]
is used in conjunction with dependency injection.
#[InjectableVersion]
is applied to a class or interface.
It denotes that it is this version and not any classes that implement/extend that should be used in the codebase.
E.g.
This also works for collections:
By default, only constructor arguments are checked. Most DI should be done via constructor injection.
In cases where dependencies are injected by methods that aren't constructors, the method must be marked with a #[CheckInjectableVersion]
:
Override
The #[Override]
attribute is used to denote that a method is overriding a method in a parent class. This is the functionality is similar to the @override
annotation in Java.
This is temporary until PHP 8.3 is released. See the RFC that will be implemented in PHP 8.3.
NOTE:
- If you are using PHP 8.3 then use the real
#[Override]
attribute. - This implementation doesn't consider traits.
RestrictTraitTo
This limits the use of a Trait to only be used by a specified class of a child of that class.
E.g. this trait is limited to classes that are or extend Controller
This would be allowed:
But this would NOT be allowed:
Sealed
This is inspired by the rejected sealed classes RFC
The #[Sealed]
attribute takes a list of classes or interfaces that can extend/implement the class/interface.
E.g.
TestTag
The #[TestTag]
attribute is an idea borrowed from hardware testing. Classes or methods marked with this attribute are only available to test code.
E.g.
NOTES:
- Classes with the
#[TestTag]
will have an error when any interaction with the class is done. - Methods with the
#[TestTag]
MUST have public visibility. - For determining what is "test code" see the relevant plugin. E.g. the PHPStan extension can be setup to either:
- Assume all classes that end
Test
is test code. See className config option. - Assume all classes within a given namespace is test code. See namespace config option.
- Assume all classes that end
Deprecated Attributes
Package (deprecated)
The #[Package]
attribute acts like an extra visibility modifier like public
, protected
and private
. It is inspired by Java's package
visibility modifier.
The #[Package]
attribute limits the visibility of a class or method to only being accessible from code in the same namespace.
This has been replaced by the #[NamespaceVisibility]
attribute. To upgrade replace:
#[Package]
with #[NamespaceVisibility(excludeSubNamespaces=true)]
NOTES:
- If adding the
#[Package]
to a method, this method MUST have public visibility. - If a class is marked with
#[Package]
then all its public methods are treated as having package visibility. - This is currently limited to method calls (including
__construct
). - Namespaces must match exactly. E.g. a package level method in
Foo\Bar
is only accessible fromFoo\Bar
. It is not accessible fromFoo
orFoo\Bar\Baz
Further examples
More detailed examples of how to use attributes is found in examples.
Contributing
See Contributing.