Skip to content

Commit

Permalink
Remove runtime reflection from CallbackRuntimeMeta, Callback
Browse files Browse the repository at this point in the history
  • Loading branch information
mabar committed Feb 22, 2025
1 parent 069316a commit e54a416
Show file tree
Hide file tree
Showing 17 changed files with 247 additions and 113 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- `Options` - `withProcessedClass()`, `getProcessedClass()` - no longer used
- Runtime reflection (performance optimization), from:
- `PropertyContext`
- `CallbackRuntimeMeta`
- `Callback`

## [0.3.0](https://github.com/orisai/object-mapper/compare/0.2.0...0.3.0) - 2025-01-21

Expand Down
16 changes: 9 additions & 7 deletions src/Callbacks/AfterMappingCallback.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Orisai\ObjectMapper\Callbacks\Context\ObjectContext;
use Orisai\ObjectMapper\MappedObject;
use Orisai\ObjectMapper\Meta\Context\MetaContext;
use Orisai\ObjectMapper\Meta\Runtime\PhpMethodMeta;
use Orisai\ObjectMapper\Processing\ObjectHolder;
use ReflectionClass;
use ReflectionMethod;
Expand Down Expand Up @@ -67,7 +68,9 @@ public static function resolveArgs(
));
}

return new AfterMappingCallbackArgs($methodName);
return new AfterMappingCallbackArgs(
PhpMethodMeta::from($method),
);
}

/**
Expand Down Expand Up @@ -212,20 +215,19 @@ public static function invoke(
$data,
Args $args,
ObjectHolder $holder,
CallbackBaseContext $context,
ReflectionClass $declaringClass
CallbackBaseContext $context
)
{
$method = $args->method;
$methodInst = $declaringClass->getMethod($method);
$meta = $args->meta;
$method = $meta->method;

$instance = $holder->getInstance();

// phpcs:disable SlevomatCodingStandard.Functions.StaticClosure.ClosureNotStatic
$methodInst->isPublic()
$meta->isPubliclyCallable
? $instance->$method($context)
: (fn () => $instance->$method($context))
->bindTo($instance, $declaringClass->getName())();
->bindTo($instance, $meta->declaringClass)();
// phpcs:enable

return [];
Expand Down
7 changes: 4 additions & 3 deletions src/Callbacks/AfterMappingCallbackArgs.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@
namespace Orisai\ObjectMapper\Callbacks;

use Orisai\ObjectMapper\Args\Args;
use Orisai\ObjectMapper\Meta\Runtime\PhpMethodMeta;

final class AfterMappingCallbackArgs implements Args
{

public string $method;
public PhpMethodMeta $meta;

public function __construct(string $method)
public function __construct(PhpMethodMeta $meta)
{
$this->method = $method;
$this->meta = $meta;
}

}
4 changes: 1 addition & 3 deletions src/Callbacks/Callback.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ public static function getArgsType(): string;
* @param T_ARGS $args
* @param ObjectContext|FieldContext $context
* @param ObjectHolder<MappedObject> $holder
* @param ReflectionClass<covariant MappedObject> $declaringClass
* @return mixed
* @throws ValueDoesNotMatch
* @throws InvalidData
Expand All @@ -47,8 +46,7 @@ public static function invoke(
$data,
Args $args,
ObjectHolder $holder,
CallbackBaseContext $context,
ReflectionClass $declaringClass
CallbackBaseContext $context
);

}
33 changes: 12 additions & 21 deletions src/Callbacks/ValidationCallback.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Orisai\ObjectMapper\Callbacks\Context\ObjectContext;
use Orisai\ObjectMapper\MappedObject;
use Orisai\ObjectMapper\Meta\Context\MetaContext;
use Orisai\ObjectMapper\Meta\Runtime\PhpMethodMeta;
use Orisai\ObjectMapper\Processing\ObjectHolder;
use ReflectionClass;
use ReflectionMethod;
Expand Down Expand Up @@ -73,6 +74,7 @@ public static function resolveArgs(
}

if ($reflector instanceof ReflectionProperty) {
/** @var ReflectionClass<MappedObject> $class */
$class = $reflector->getDeclaringClass();
$property = $reflector;
} else {
Expand All @@ -83,10 +85,8 @@ public static function resolveArgs(
$method = self::validateMethod($class, $property, $methodName);

return new ValidationCallbackArgs(
$methodName,
$method->isStatic(),
self::getMethodReturnsValue($method),
CallbackRuntime::from($runtime),
PhpMethodMeta::from($method),
);
}

Expand Down Expand Up @@ -272,14 +272,6 @@ protected static function getTypeName(?ReflectionType $type): ?string
return $type->getName();
}

/**
* Method is expected to return data unless void or never return type is defined
*/
private static function getMethodReturnsValue(ReflectionMethod $method): bool
{
return !in_array(self::getTypeName($method->getReturnType()), ['void', 'never'], true);
}

public static function getArgsType(): string
{
return ValidationCallbackArgs::class;
Expand All @@ -293,8 +285,7 @@ public static function invoke(
$data,
Args $args,
ObjectHolder $holder,
CallbackBaseContext $context,
ReflectionClass $declaringClass
CallbackBaseContext $context
)
{
// Callback is skipped for unsupported runtime
Expand All @@ -303,28 +294,28 @@ public static function invoke(
return $data;
}

$method = $args->method;
$methodInst = $declaringClass->getMethod($method);
$meta = $args->meta;
$method = $meta->method;

if ($args->isStatic) {
if ($meta->isStatic) {
$class = $holder->getClass();

$callbackOutput = $methodInst->isPublic()
$callbackOutput = $meta->isPubliclyCallable
? $class::$method($data, $context)
: (static fn () => $class::$method($data, $context))
->bindTo(null, $declaringClass->getName())();
->bindTo(null, $meta->declaringClass)();
} else {
$instance = $holder->getInstance();

// phpcs:disable SlevomatCodingStandard.Functions.StaticClosure.ClosureNotStatic
$callbackOutput = $methodInst->isPublic()
$callbackOutput = $meta->isPubliclyCallable
? $instance->$method($data, $context)
: (fn () => $instance->$method($data, $context))
->bindTo($instance, $declaringClass->getName())();
->bindTo($instance, $meta->declaringClass)();
// phpcs:enable
}

return $args->returnsValue ? $callbackOutput : $data;
return $meta->returnsValue ? $callbackOutput : $data;
}

}
20 changes: 5 additions & 15 deletions src/Callbacks/ValidationCallbackArgs.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,19 @@
namespace Orisai\ObjectMapper\Callbacks;

use Orisai\ObjectMapper\Args\Args;
use Orisai\ObjectMapper\Meta\Runtime\PhpMethodMeta;

final class ValidationCallbackArgs implements Args
{

public string $method;

public bool $isStatic;

public bool $returnsValue;

public CallbackRuntime $runtime;

public function __construct(
string $method,
bool $isStatic,
bool $returnsValue,
CallbackRuntime $runtime
)
public PhpMethodMeta $meta;

public function __construct(CallbackRuntime $runtime, PhpMethodMeta $meta)
{
$this->method = $method;
$this->isStatic = $isStatic;
$this->returnsValue = $returnsValue;
$this->runtime = $runtime;
$this->meta = $meta;
}

}
15 changes: 5 additions & 10 deletions src/Meta/MetaResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ private function resolveClassMeta(ReflectionClass $rootClass, CompileMeta $meta)

$context = new MetaContext($this->loader, $this);

$callbacksByMeta[] = $this->resolveCallbacksMeta($classMeta, $context, $reflector, $reflector);
$callbacksByMeta[] = $this->resolveCallbacksMeta($classMeta, $context, $reflector);
$docsByMeta[] = $this->resolveDocsMeta($classMeta, $context);
$modifiersByMeta[] = $this->resolveClassModifiersMeta($classMeta, $context);
}
Expand Down Expand Up @@ -252,7 +252,7 @@ private function resolveFieldMeta(
$context = new MetaFieldContext($this->loader, $this, $defaultValue);

return new FieldRuntimeMeta(
$this->resolveCallbacksMeta($meta, $context, $reflector, $classReflector),
$this->resolveCallbacksMeta($meta, $context, $reflector),
$this->resolveDocsMeta($meta, $context),
$this->resolveFieldModifiersMeta($meta, $context),
$this->resolveRuleMeta(
Expand Down Expand Up @@ -298,14 +298,12 @@ private function throwFieldMetaOutsideOfMappedObject(

/**
* @param ReflectionClass<MappedObject>|ReflectionProperty $reflector
* @param ReflectionClass<MappedObject> $classReflector
* @return array<class-string<Callback<Args>>, list<CallbackRuntimeMeta<Args>>>
*/
private function resolveCallbacksMeta(
NodeCompileMeta $meta,
MetaContext $context,
Reflector $reflector,
ReflectionClass $classReflector
Reflector $reflector
): array
{
$array = [];
Expand All @@ -314,7 +312,6 @@ private function resolveCallbacksMeta(
$callback,
$context,
$reflector,
$classReflector,
);

$array[$callbackMeta->type][] = $callbackMeta;
Expand All @@ -325,14 +322,12 @@ private function resolveCallbacksMeta(

/**
* @param ReflectionClass<MappedObject>|ReflectionProperty $reflector
* @param ReflectionClass<MappedObject> $declaringClass
* @return CallbackRuntimeMeta<Args>
*/
private function resolveCallbackMeta(
CallbackCompileMeta $meta,
MetaContext $context,
Reflector $reflector,
ReflectionClass $declaringClass
Reflector $reflector
): CallbackRuntimeMeta
{
$type = $meta->getType();
Expand All @@ -349,7 +344,7 @@ private function resolveCallbackMeta(
);
}

return new CallbackRuntimeMeta($type, $args, $declaringClass);
return new CallbackRuntimeMeta($type, $args);
}

/**
Expand Down
13 changes: 2 additions & 11 deletions src/Meta/Runtime/CallbackRuntimeMeta.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@

use Orisai\ObjectMapper\Args\Args;
use Orisai\ObjectMapper\Callbacks\Callback;
use Orisai\ObjectMapper\MappedObject;
use ReflectionClass;

/**
* @phpstan-type T_SERIALIZED array{type: class-string<Callback<T>>, args: T, declaringClass: class-string<MappedObject>}
* @phpstan-type T_SERIALIZED array{type: class-string<Callback<T>>, args: T}
*
* @template-covariant T of Args
*
Expand All @@ -23,19 +21,14 @@ final class CallbackRuntimeMeta
/** @var T */
public Args $args;

/** @var ReflectionClass<covariant MappedObject> */
public ReflectionClass $declaringClass;

/**
* @param class-string<Callback<T>> $type
* @param T $args
* @param ReflectionClass<covariant MappedObject> $declaringClass
*/
public function __construct(string $type, Args $args, ReflectionClass $declaringClass)
public function __construct(string $type, Args $args)
{
$this->type = $type;
$this->args = $args;
$this->declaringClass = $declaringClass;
}

/**
Expand All @@ -46,7 +39,6 @@ public function __serialize(): array
return [
'type' => $this->type,
'args' => $this->args,
'declaringClass' => $this->declaringClass->getName(),
];
}

Expand All @@ -57,7 +49,6 @@ public function __unserialize(array $data): void
{
$this->type = $data['type'];
$this->args = $data['args'];
$this->declaringClass = new ReflectionClass($data['declaringClass']);
}

}
Loading

0 comments on commit e54a416

Please sign in to comment.