arnapou / ensure
Library - Simple library to make safer php code for SA tools.
Requires
- php: ~8.3.0 || ~8.4.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.52
- phpstan/extension-installer: ^1.3
- phpstan/phpstan: ^2.0
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-phpunit: ^2.0
- phpstan/phpstan-strict-rules: ^2.0
- phpunit/php-code-coverage: ^11.0
- phpunit/phpunit: ^11.0
README
This library is a simple tool to have a safer php code.
We want to 'ensure' or 'enforce' the type check for quality reasons and/or for Static Analysis tools like PHPStan or Psalm.
Installation
composer require arnapou/ensure
packagist đī¸ arnapou/ensure
Ensure
In the example below, we guarantee the fact that a non-constrained int
or string
are constrained into the class.
use Arnapou\Ensure\Ensure;
use Arnapou\Ensure\Expected;
class MyObject
{
/** @var positive-int */
public int $id;
/** @var non-empty-string */
public string $name;
/**
* @throws Expected
*/
public function __construct(int $id, string $name)
{
$this->id = Ensure::positiveInt($id);
$this->name = Ensure::nonEmptyString($name);
}
}
Enforce
In the example below, which can be from a legacy code, we have a phpdoc type-hinting in the construct.
But it is not "hard" enough from a php point of view, and it may be too risky to change the mixed
type-hinting.
You can guaranty the type hinting inside the class while staying lax on type-check by using Enforce
.
It will cast the value when it is enough "safe" to do it :
- Examples of valid/auto-casted
int
:"1234"
,"1.2e3"
,3.0
,true
- Examples of invalid
int
:"foo"
,"1.234e2"
,3.14
,[]
use Arnapou\Ensure\Enforce;
use Arnapou\Ensure\Expected;
class MyObject
{
/** @var positive-int */
public int $id;
/** @var non-empty-string */
public string $name;
/**
* @param int $id
* @param string $name
*
* @throws Expected
*/
public function __construct(mixed $id, mixed $name)
{
$this->id = Enforce::positiveInt($id);
$this->name = Enforce::nonEmptyString($name);
}
}
Message customization or translation
You can do that implementing your own MessageFactoryInterface
and then set it as default for Expected
class.
class MyMessageFactory implements MessageFactoryInterface
{
public function createExpectedMessage(string $expected, int $code, mixed $value, string $propertyName, mixed ...$parameters): string
{
// Build the message here.
}
}
// Change the default message factory.
\Arnapou\Ensure\Expected::setMessageFactory(new MyMessageFactory());
âšī¸ The default MessageFactory implementation is final
,
you cannot extend it, but you can reuse it with composition if necessary :
class MyMessageFactory implements MessageFactoryInterface
{
private \Arnapou\Ensure\MessageFactory\MessageFactory $internal;
public function __construct(){
$this->internal = new \Arnapou\Ensure\MessageFactory\MessageFactory();
}
public function createExpectedMessage(string $expected, int $code, mixed $value, string $propertyName, mixed ...$parameters): string
{
if (/* any logic you need */) {
// Your customization here
}
// Default on the default message factory
return $this->internal->createExpectedMessage($expected, $code, $value, $propertyName, ...$parameters);
}
}
// Change the default message factory.
\Arnapou\Ensure\Expected::setMessageFactory(new MyMessageFactory());
Php versions
Date | Ref | 8.4 | 8.3 | 8.2 |
---|---|---|---|---|
24/11/2024 | 2.7.x, main | Ã | Ã | |
25/11/2023 | 2.0 - 2.6 | Ã | ||
17/05/2024 | 1.4.x | Ã | Ã | |
23/08/2023 | 1.x | Ã |