Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature - refactor framework core to php82 #493

Merged
merged 2 commits into from
Apr 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion demos/Demo/Aspect/PropertyInterceptorAspect.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

use Go\Aop\Aspect;
use Go\Aop\Intercept\FieldAccess;
use Go\Aop\Intercept\FieldAccessType;
use Go\Lang\Attribute\Around;

/**
Expand All @@ -29,7 +30,7 @@ class PropertyInterceptorAspect implements Aspect
#[Around("access(public|protected|private Demo\Example\PropertyDemo->*)")]
public function aroundFieldAccess(FieldAccess $fieldAccess): void
{
$isRead = $fieldAccess->getAccessType() == FieldAccess::READ;
$isRead = $fieldAccess->getAccessType() === FieldAccessType::READ;
// proceed all internal advices
$fieldAccess->proceed();

Expand Down
90 changes: 45 additions & 45 deletions src/Aop/Framework/AbstractInterceptor.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
namespace Go\Aop\Framework;

use Closure;
use Go\Aop\AspectException;
use Go\Aop\Intercept\Interceptor;
use Go\Aop\OrderedAdvice;
use Go\Core\AspectKernel;
use ReflectionFunction;
use ReflectionMethod;
Expand All @@ -31,7 +33,8 @@
*
* After and before interceptors are simple closures that will be invoked after and before main invocation.
*
* Framework models an interceptor as an PHP-closure, maintaining a chain of interceptors "around" the joinpoint:
* Framework models an interceptor as an PHP {@see Closure}, maintaining a chain of interceptors "around" the joinpoint:
* <pre>
* public function (Joinpoint $joinPoint)
* {
* echo 'Before action';
Expand All @@ -41,98 +44,95 @@
*
* return $result;
* }
* </pre>
*/
abstract class AbstractInterceptor implements Interceptor, OrderedAdvice
{
/**
* Local cache of advices for faster unserialization on big projects
*
* @var array<Closure>
*/
protected static array $localAdvicesCache = [];

/**
* Pointcut expression string which was used for this interceptor
*/
protected string $pointcutExpression;

/**
* Closure to call
*/
protected Closure $adviceMethod;

/**
* Advice order
* @var (array&array<string, Closure>) Local hashmap of advices for faster unserialization
*/
private int $adviceOrder;
private static array $localAdvicesCache = [];

/**
* Default constructor for interceptor
*/
public function __construct(Closure $adviceMethod, int $adviceOrder = 0, string $pointcutExpression = '')
{
$this->adviceMethod = $adviceMethod;
$this->adviceOrder = $adviceOrder;
$this->pointcutExpression = $pointcutExpression;
}
public function __construct(
protected readonly Closure $adviceMethod,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line indented incorrectly; expected 4 spaces, found 8

private readonly int $adviceOrder = 0,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line indented incorrectly; expected 4 spaces, found 8

protected readonly string $pointcutExpression = ''

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line indented incorrectly; expected 4 spaces, found 8

) {}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Closing brace must be on a line by itself


/**
* Serialize advice method into array
* Serializes advice closure into array
*
* @return array{name: string, class?: string}
*/
public static function serializeAdvice(Closure $adviceMethod): array
{
$refAdvice = new ReflectionFunction($adviceMethod);
$reflectionAdvice = new ReflectionFunction($adviceMethod);
$scopeReflectionClass = $reflectionAdvice->getClosureScopeClass();

$packedAdvice = ['name' => $reflectionAdvice->name];
if (!isset($scopeReflectionClass)) {
throw new AspectException('Could not pack an interceptor without aspect name');
}
$packedAdvice['class'] = $scopeReflectionClass->name;

return [
'method' => $refAdvice->name,
'class' => $refAdvice->getClosureScopeClass()->name
];
return $packedAdvice;
}

/**
* Unserialize an advice
*
* @param array $adviceData Information about advice
* @param array{name: string, class?: string} $adviceData Information about advice
*/
public static function unserializeAdvice(array $adviceData): Closure
{
// General unpacking supports only aspect's advices
if (!isset($adviceData['class'])) {
throw new AspectException('Could not unpack an interceptor without aspect name');
}
$aspectName = $adviceData['class'];
$methodName = $adviceData['method'];
$methodName = $adviceData['name'];

if (!isset(static::$localAdvicesCache["$aspectName->$methodName"])) {
$aspect = AspectKernel::getInstance()->getContainer()->getAspect($aspectName);
$refMethod = new ReflectionMethod($aspectName, $methodName);
$advice = $refMethod->getClosure($aspect);
// With aspect name and method name, we can restore back a closure for it
if (!isset(self::$localAdvicesCache["$aspectName->$methodName"])) {
$aspect = AspectKernel::getInstance()->getContainer()->getAspect($aspectName);
$advice = (new ReflectionMethod($aspectName, $methodName))->getClosure($aspect);

static::$localAdvicesCache["$aspectName->$methodName"] = $advice;
assert(isset($advice), 'getClosure() can not be null on modern PHP versions');
self::$localAdvicesCache["$aspectName->$methodName"] = $advice;
}

return static::$localAdvicesCache["$aspectName->$methodName"];
return self::$localAdvicesCache["$aspectName->$methodName"];
}

/**
* Returns the advice order
*/
public function getAdviceOrder(): int
{
return $this->adviceOrder;
}

/**
* Getter for extracting the advice closure from Interceptor
*
* @internal
*/
public function getRawAdvice(): Closure
{
return $this->adviceMethod;
}

/**
* Serializes an interceptor into it's representation
* Serializes an interceptor into it's array shape representation
*
* @return non-empty-array<string, mixed>
*/
final public function __serialize(): array
{
// Compressing state representation to avoid default values, eg pointcutExpression = '' or adviceOrder = 0
$state = array_filter(get_object_vars($this));

// Override closure with array representation to enable serialization
$state['adviceMethod'] = static::serializeAdvice($this->adviceMethod);

return $state;
Expand All @@ -141,7 +141,7 @@ final public function __serialize(): array
/**
* Un-serializes an interceptor from it's stored state
*
* @param array $state The stored representation of the interceptor.
* @param array{adviceMethod: array{name: string, class?: string}} $state The stored representation of the interceptor.
*/
final public function __unserialize(array $state): void
{
Expand Down
16 changes: 3 additions & 13 deletions src/Aop/Framework/AbstractInvocation.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,16 @@
abstract class AbstractInvocation extends AbstractJoinpoint implements Invocation
{
/**
* Arguments for invocation
* @var array<mixed> Arguments for invocation, can be mutated by the {@see setArguments()} method
*/
protected array $arguments = [];

/**
* Gets arguments for current invocation
*
* @api
*/
public function getArguments(): array
final public function getArguments(): array
{
return $this->arguments;
}

/**
* Sets arguments for current invocation
*
* @api
*/
public function setArguments(array $arguments): void
final public function setArguments(array $arguments): void
{
$this->arguments = $arguments;
}
Expand Down
50 changes: 11 additions & 39 deletions src/Aop/Framework/AbstractJoinpoint.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@
use Go\Aop\AdviceBefore;
use Go\Aop\Intercept\Interceptor;
use Go\Aop\Intercept\Joinpoint;

use function is_array;
use Go\Aop\OrderedAdvice;

/**
* Abstract joinpoint for framework
Expand All @@ -33,26 +32,11 @@
*/
abstract class AbstractJoinpoint implements Joinpoint
{
/**
* List of advices (interceptors)
*
* NB: All current children assume that each advice is Interceptor now.
* Whereas, it isn't correct logically, this can be used to satisfy PHPStan check now.
*
* @var array<Interceptor>
*/
protected array $advices = [];

/**
* Current advice index
*/
protected int $current = 0;

/**
* Stack frames to work with recursive calls or with cross-calls inside object
*/
protected array $stackFrames = [];

/**
* Recursion level for invocation
*/
Expand All @@ -63,10 +47,7 @@ abstract class AbstractJoinpoint implements Joinpoint
*
* @param array<Interceptor> $advices List of advices (interceptors)
*/
public function __construct(array $advices)
{
$this->advices = $advices;
}
public function __construct(protected readonly array $advices = []) {}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Line indented incorrectly; expected 0 spaces, found 4
  • Opening brace should be on a new line
  • Closing brace must be on a line by itself


/**
* Sorts advices by priority
Expand All @@ -80,23 +61,12 @@ public static function sortAdvices(array $advices): array
$sortedAdvices = $advices;
uasort(
$sortedAdvices,
function (Advice $first, Advice $second) {
switch (true) {
case $first instanceof AdviceBefore && !($second instanceof AdviceBefore):
return -1;

case $first instanceof AdviceAround && !($second instanceof AdviceAround):
return 1;

case $first instanceof AdviceAfter && !($second instanceof AdviceAfter):
return $second instanceof AdviceBefore ? 1 : -1;

case ($first instanceof OrderedAdvice && $second instanceof OrderedAdvice):
return $first->getAdviceOrder() - $second->getAdviceOrder();

default:
return 0;
}
fn(Advice $first, Advice $second) => match (true) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Space before opening parenthesis of function call prohibited

$first instanceof AdviceBefore && !($second instanceof AdviceBefore) => -1,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Multi-line function call not indented correctly; expected 12 spaces but found 16

$first instanceof AdviceAround && !($second instanceof AdviceAround) => 1,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Multi-line function call not indented correctly; expected 12 spaces but found 16

$first instanceof AdviceAfter && !($second instanceof AdviceAfter) => $second instanceof AdviceBefore ? 1 : -1,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Multi-line function call not indented correctly; expected 12 spaces but found 16

$first instanceof OrderedAdvice && $second instanceof OrderedAdvice => $first->getAdviceOrder() - $second->getAdviceOrder(),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Multi-line function call not indented correctly; expected 12 spaces but found 16

default => 0,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Multi-line function call not indented correctly; expected 12 spaces but found 16
  • Line indented incorrectly; expected 4 spaces, found 16

}
);

Expand All @@ -106,7 +76,9 @@ function (Advice $first, Advice $second) {
/**
* Replace concrete advices with list of ids
*
* @param Advice[][][] $advices List of advices
* @param array<array<array<string, Advice|Interceptor>>> $advices List of advices
*
* @return array<array<array<string>>> Sorted identifier of advices/interceptors
*/
public static function flatAndSortAdvices(array $advices): array
{
Expand Down
Loading
Loading