Skip to content

Commit

Permalink
improves
Browse files Browse the repository at this point in the history
rodber committed Dec 16, 2023
1 parent 0785c0f commit 529ad37
Showing 5 changed files with 148 additions and 17 deletions.
49 changes: 49 additions & 0 deletions src/Attributes/CallableAttr.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

/*
* This file is part of Chevere.
*
* (c) Rodolfo Berrios <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Chevere\Parameter\Attributes;

use Attribute;
use Chevere\Parameter\Interfaces\ParameterAttributeInterface;
use Chevere\Parameter\Interfaces\ParameterInterface;
use LogicException;
use function Chevere\Parameter\object;

#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_FUNCTION)]
class CallableAttr implements ParameterAttributeInterface
{
public readonly ParameterInterface $parameter;

public function __construct(callable $callable)
{
$return = $callable();
object(ParameterInterface::class)($return);

Check warning on line 30 in src/Attributes/CallableAttr.php

GitHub Actions / PHP 8.1 test on ubuntu-latest

Escaped Mutant for Mutator "FunctionCallRemoval": --- Original +++ New @@ @@ public function __construct(callable $callable) { $return = $callable(); - object(ParameterInterface::class)($return); + // if (!is_object($return)) { // throw new LogicException('DynamicAttr must return an object'); // }

Check warning on line 30 in src/Attributes/CallableAttr.php

GitHub Actions / PHP 8.2 test on ubuntu-latest

Escaped Mutant for Mutator "FunctionCallRemoval": --- Original +++ New @@ @@ public function __construct(callable $callable) { $return = $callable(); - object(ParameterInterface::class)($return); + // if (!is_object($return)) { // throw new LogicException('DynamicAttr must return an object'); // }

Check warning on line 30 in src/Attributes/CallableAttr.php

GitHub Actions / PHP 8.3 test on ubuntu-latest

Escaped Mutant for Mutator "FunctionCallRemoval": --- Original +++ New @@ @@ public function __construct(callable $callable) { $return = $callable(); - object(ParameterInterface::class)($return); + // if (!is_object($return)) { // throw new LogicException('DynamicAttr must return an object'); // }
// if (!is_object($return)) {
// throw new LogicException('DynamicAttr must return an object');
// }
// if (! $return instanceof ParameterInterface) {
// throw new LogicException('DynamicAttr must return an object implementing ParameterInterface');
// }
$this->parameter = $return;
}

public function __invoke(mixed $mixed): mixed
{
return $this->parameter->__invoke($mixed);
}

public function parameter(): ParameterInterface
{
return $this->parameter;
}
}
44 changes: 44 additions & 0 deletions src/Attributes/NullAttr.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

/*
* This file is part of Chevere.
*
* (c) Rodolfo Berrios <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Chevere\Parameter\Attributes;

use Attribute;
use Chevere\Parameter\Interfaces\NullParameterInterface;
use Chevere\Parameter\Interfaces\ParameterAttributeInterface;
use Chevere\Parameter\Interfaces\ParameterInterface;
use function Chevere\Parameter\null;

#[Attribute(Attribute::TARGET_PROPERTY | Attribute::TARGET_PARAMETER | Attribute::TARGET_CLASS_CONSTANT)]
class NullAttr implements ParameterAttributeInterface
{
public readonly NullParameterInterface $parameter;

public function __construct(
string $description = '',
) {
$this->parameter = null(
description: $description,
);
}

public function __invoke(mixed $null): mixed
{
return $this->parameter->__invoke($null);
}

public function parameter(): ParameterInterface
{
return $this->parameter;
}
}
40 changes: 33 additions & 7 deletions src/Attributes/functions.php
Original file line number Diff line number Diff line change
@@ -18,6 +18,7 @@
use ReflectionAttribute;
use ReflectionFunction;
use ReflectionMethod;
use Throwable;
use function Chevere\Parameter\parameterAttr;
use function Chevere\Parameter\reflectionToParameters;

@@ -99,11 +100,14 @@ function arrayArguments(string $name): ArgumentsInterface
}

/**
* Validates argument `$name` against attribute rules.
* Validates argument `$name` against parameter attribute rules.
*
* @param ?string $name Argument name or `null` to validate all arguments.
*/
function validate(?string $name = null): void
function valid(?string $name = null): void
{
$caller = debug_backtrace(0, 2)[1];
$trace = debug_backtrace(0, 2);
$caller = $trace[1];
$class = $caller['class'] ?? false;
$method = $caller['function'];
$args = $caller['args'] ?? [];
@@ -122,17 +126,29 @@ function validate(?string $name = null): void

return;
}
$parameters->get($name)->__invoke($arguments[$name]);

try {
$parameters->get($name)->__invoke($arguments[$name]);
} catch (Throwable $e) {
$invoker = $trace[0];
// @phpstan-ignore-next-line
$fileLine = $invoker['file'] . ':' . $invoker['line'];

throw new $e(
$e->getMessage() . ' >>> ' . $fileLine
);
}
}

/**
* Validates `$var` against the return attribute.
*
* @return mixed The validated `$var`.
*/
function returnAttr(mixed $var): mixed
function validReturn(mixed $var): mixed
{
$caller = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1];
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
$caller = $trace[1];
$class = $caller['class'] ?? null;
$method = $caller['function'];
$reflection = $class
@@ -142,5 +158,15 @@ function returnAttr(mixed $var): mixed
$attribute = $reflection->getAttributes(ReturnAttr::class)[0]
?? throw new LogicException('No return attribute found');

return $attribute->newInstance()->__invoke($var);
try {
return $attribute->newInstance()->__invoke($var);
} catch (Throwable $e) {
$invoker = $trace[0];
// @phpstan-ignore-next-line
$fileLine = $invoker['file'] . ':' . $invoker['line'];

throw new $e(
$e->getMessage() . ' >>> ' . $fileLine
);
}
}
28 changes: 20 additions & 8 deletions tests/src/UsesParameterAttributes.php
Original file line number Diff line number Diff line change
@@ -14,20 +14,26 @@
namespace Chevere\Tests\src;

use Chevere\Parameter\Attributes\ArrayAttr;
use Chevere\Parameter\Attributes\CallableAttr;
use Chevere\Parameter\Attributes\GenericAttr;
use Chevere\Parameter\Attributes\IntAttr;
use Chevere\Parameter\Attributes\ReturnAttr;
use Chevere\Parameter\Attributes\StringAttr;
use Chevere\Parameter\Interfaces\ParameterInterface;
use function Chevere\Parameter\Attributes\arrayArguments;
use function Chevere\Parameter\Attributes\arrayAttr;
use function Chevere\Parameter\Attributes\genericAttr;
use function Chevere\Parameter\Attributes\intAttr;
use function Chevere\Parameter\Attributes\returnAttr;
use function Chevere\Parameter\Attributes\stringAttr;
use function Chevere\Parameter\Attributes\validate;
use function Chevere\Parameter\Attributes\valid;
use function Chevere\Parameter\Attributes\validReturn;
use function Chevere\Parameter\int;

final class UsesParameterAttributes
{
#[ReturnAttr(
new CallableAttr(__CLASS__ . '::acceptResponse')
)]
public function __construct(
#[StringAttr('/^[A-Za-z]+$/')]
string $name = 'Test',
@@ -42,23 +48,29 @@ public function __construct(
)]
iterable $tags = [],
) {
validate('name');
validate('age');
validate('cols');
validate('tags');
validate();
valid('name');
valid('age');
valid('cols');
valid('tags');
valid();
$name = stringAttr('name')($name);
$age = intAttr('age')($age);
$cols = arrayAttr('cols')($cols);
$id = arrayArguments('cols')->required('id')->int();
$tags = genericAttr('tags')($tags);
validReturn($id);
}

public static function acceptResponse(): ParameterInterface
{
return int();
}

#[ReturnAttr(
new IntAttr(min: 0, max: 5)
)]
public function run(int $int): int
{
return returnAttr($int);
return validReturn($int);
}
}
4 changes: 2 additions & 2 deletions tests/src/functions.php
Original file line number Diff line number Diff line change
@@ -19,7 +19,7 @@
use Chevere\Parameter\Attributes\IntAttr;
use Chevere\Parameter\Attributes\ReturnAttr;
use Chevere\Parameter\Attributes\StringAttr;
use function Chevere\Parameter\Attributes\validate;
use function Chevere\Parameter\Attributes\valid;

#[ReturnAttr(
new BoolAttr()
@@ -37,7 +37,7 @@ function myArray(
)]
array $spooky
): bool {
validate('spooky');
valid('spooky');

return true;
}

0 comments on commit 529ad37

Please sign in to comment.