Skip to content

Commit

Permalink
Remove runtime reflection from FieldRutimeMeta
Browse files Browse the repository at this point in the history
  • Loading branch information
mabar committed Feb 22, 2025
1 parent 8322fd9 commit 5bab92b
Show file tree
Hide file tree
Showing 8 changed files with 126 additions and 30 deletions.
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- `DefaultProcessor`
- Simplify finding missing fields (performance optimization)
- Reduce calls needed to find field names for "did you mean" error helper (performance optimization)
- Call `unset()` only for initialized properties (performance optimization)
- Create functions for setting and unsetting non public-set properties only once (performance optimization)
- Callbacks
- renamed
Expand Down Expand Up @@ -62,9 +61,10 @@ 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`
- `PropertyContext`
- `FieldRuntimeMeta`

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

Expand Down
5 changes: 3 additions & 2 deletions src/Meta/MetaResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
use Orisai\ObjectMapper\Meta\Runtime\ClassRuntimeMeta;
use Orisai\ObjectMapper\Meta\Runtime\FieldRuntimeMeta;
use Orisai\ObjectMapper\Meta\Runtime\ModifierRuntimeMeta;
use Orisai\ObjectMapper\Meta\Runtime\PhpPropertyMeta;
use Orisai\ObjectMapper\Meta\Runtime\RuleRuntimeMeta;
use Orisai\ObjectMapper\Meta\Runtime\RuntimeMeta;
use Orisai\ObjectMapper\Meta\Shared\DefaultValueMeta;
Expand Down Expand Up @@ -217,7 +218,7 @@ private function propertyNameToFieldName(FieldRuntimeMeta $fieldMeta)
return $modifier->args->name;
}

return $fieldMeta->property->getName();
return $fieldMeta->property->name;
}

/**
Expand Down Expand Up @@ -260,7 +261,7 @@ private function resolveFieldMeta(
$context,
),
$defaultValue,
$reflector,
PhpPropertyMeta::from($reflector),
);
}

Expand Down
10 changes: 4 additions & 6 deletions src/Meta/Runtime/FieldRuntimeMeta.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
use Orisai\ObjectMapper\Args\Args;
use Orisai\ObjectMapper\Meta\Shared\DefaultValueMeta;
use Orisai\ObjectMapper\Modifiers\Modifier;
use ReflectionProperty;

final class FieldRuntimeMeta extends NodeRuntimeMeta
{
Expand All @@ -15,7 +14,7 @@ final class FieldRuntimeMeta extends NodeRuntimeMeta

public DefaultValueMeta $default;

public ReflectionProperty $property;
public PhpPropertyMeta $property;

/** @var array<class-string<Modifier<Args>>, ModifierRuntimeMeta<Args>> */
public array $modifiers;
Expand All @@ -31,7 +30,7 @@ public function __construct(
array $modifiers,
RuleRuntimeMeta $rule,
DefaultValueMeta $default,
ReflectionProperty $property
PhpPropertyMeta $property
)
{
parent::__construct($callbacks, $docs);
Expand Down Expand Up @@ -60,8 +59,7 @@ public function __serialize(): array
'parent' => parent::__serialize(),
'rule' => $this->rule,
'default' => $this->default,
'class' => $this->property->getDeclaringClass()->getName(),
'property' => $this->property->getName(),
'property' => $this->property,
'modifiers' => $this->modifiers,
];
}
Expand All @@ -74,7 +72,7 @@ public function __unserialize(array $data): void
parent::__unserialize($data['parent']);
$this->rule = $data['rule'];
$this->default = $data['default'];
$this->property = new ReflectionProperty($data['class'], $data['property']);
$this->property = $data['property'];
$this->modifiers = $data['modifiers'];
}

Expand Down
55 changes: 55 additions & 0 deletions src/Meta/Runtime/PhpPropertyMeta.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php declare(strict_types = 1);

namespace Orisai\ObjectMapper\Meta\Runtime;

use Orisai\ObjectMapper\MappedObject;
use ReflectionClass;
use ReflectionProperty;
use const PHP_VERSION_ID;

/**
* @readonly
*/
final class PhpPropertyMeta
{

/** @var class-string<MappedObject> */
public string $declaringClass;

public string $name;

public bool $isPublicSet;

/**
* @param class-string<MappedObject> $declaringClass
*/
public function __construct(
string $declaringClass,
string $name,
bool $isPublicSet
)
{
$this->declaringClass = $declaringClass;
$this->name = $name;
$this->isPublicSet = $isPublicSet;
}

public static function from(ReflectionProperty $property): self
{
/** @var ReflectionClass<MappedObject> $class */
$class = $property->getDeclaringClass();

return new self(
$class->getName(),
$property->getName(),
self::isPublicSet($property),
);
}

private static function isPublicSet(ReflectionProperty $property): bool
{
return $property->isPublic()
&& (PHP_VERSION_ID < 8_01_00 || !$property->isReadOnly());
}

}
26 changes: 10 additions & 16 deletions src/Processing/DefaultProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
use function array_map;
use function assert;
use function is_array;
use const PHP_VERSION_ID;

final class DefaultProcessor implements Processor
{
Expand Down Expand Up @@ -328,13 +327,13 @@ private function handleSentFields(
}

$property = $fieldMeta->property;
$className = $property->getDeclaringClass()->getName();
$propertyName = $property->getName();
$className = $property->declaringClass;
$propertyName = $property->name;
$propertyContext = $this->propertyContextCache[$className][$propertyName]
?? (
$this->propertyContextCache[$className][$propertyName] = new PropertyContext(
$fieldMeta->default,
$fieldMeta->property->getName(),
$fieldMeta->property->name,
$fieldName,
));

Expand Down Expand Up @@ -581,18 +580,13 @@ private function fillObject(
// Reset mapped properties state
foreach ($fieldsMeta as $fieldMeta) {
$property = $fieldMeta->property;
$declaringClass = $property->getDeclaringClass();
$name = $property->getName();

if (
$property->isInitialized($object)
&& $property->isPublic()
&& (PHP_VERSION_ID < 8_01_00 || !$property->isReadOnly())
) {
$name = $property->name;

if ($property->isPublicSet) {
unset($object->$name);
} else {
// phpcs:disable SlevomatCodingStandard.Functions.StaticClosure
$unsetter->bindTo($object, $declaringClass->getName())($object, $name);
$unsetter->bindTo($object, $property->declaringClass)($object, $name);
// phpcs:enable
}
}
Expand All @@ -603,14 +597,14 @@ private function fillObject(
// Set processed data
foreach ($data as $fieldName => $value) {
$property = $fieldsMeta[$fieldName]->property;
$name = $property->getName();
$name = $property->name;

if ($property->isPublic() && (PHP_VERSION_ID < 8_01_00 || !$property->isReadOnly())) {
if ($property->isPublicSet) {
$object->$name = $value;
} else {
$setter->bindTo(
$object,
$property->getDeclaringClass()->getName(),
$property->declaringClass,
)($object, $name, $value);
}
}
Expand Down
4 changes: 2 additions & 2 deletions tests/Unit/Meta/Runtime/FieldRuntimeMetaTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@
use Orisai\ObjectMapper\Meta\Runtime\FieldRuntimeMeta;
use Orisai\ObjectMapper\Meta\Runtime\ModifierRuntimeMeta;
use Orisai\ObjectMapper\Meta\Runtime\PhpMethodMeta;
use Orisai\ObjectMapper\Meta\Runtime\PhpPropertyMeta;
use Orisai\ObjectMapper\Meta\Runtime\RuleRuntimeMeta;
use Orisai\ObjectMapper\Meta\Shared\DefaultValueMeta;
use Orisai\ObjectMapper\Meta\Shared\DocMeta;
use Orisai\ObjectMapper\Modifiers\FieldNameArgs;
use Orisai\ObjectMapper\Modifiers\FieldNameModifier;
use Orisai\ObjectMapper\Rules\MixedRule;
use PHPUnit\Framework\TestCase;
use ReflectionProperty;
use Tests\Orisai\ObjectMapper\Doubles\NoDefaultsVO;
use function serialize;
use function unserialize;
Expand All @@ -29,7 +29,7 @@ final class FieldRuntimeMetaTest extends TestCase

public function test(): void
{
$property = new ReflectionProperty(NoDefaultsVO::class, 'string');
$property = new PhpPropertyMeta(NoDefaultsVO::class, 'property', true);

$beforeCallbacks = [
new CallbackRuntimeMeta(
Expand Down
48 changes: 48 additions & 0 deletions tests/Unit/Meta/Runtime/PhpPropertyMetaTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php declare(strict_types = 1);

namespace Tests\Orisai\ObjectMapper\Unit\Meta\Runtime;

use Generator;
use Orisai\ObjectMapper\MappedObject;
use Orisai\ObjectMapper\Meta\Runtime\PhpPropertyMeta;
use PHPUnit\Framework\TestCase;
use Tests\Orisai\ObjectMapper\Doubles\DefaultsVO;
use Tests\Orisai\ObjectMapper\Doubles\NoDefaultsVO;

final class PhpPropertyMetaTest extends TestCase
{

/**
* @param class-string<MappedObject> $declaringClass
*
* @dataProvider provide
*/
public function test(
string $declaringClass,
string $name,
bool $isPublicSet
): void
{
$meta = new PhpPropertyMeta($declaringClass, $name, $isPublicSet);

self::assertSame($declaringClass, $meta->declaringClass);
self::assertSame($name, $meta->name);
self::assertSame($isPublicSet, $meta->isPublicSet);
}

public function provide(): Generator
{
yield [
NoDefaultsVO::class,
'property',
true,
];

yield [
DefaultsVO::class,
'anotherProperty',
false,
];
}

}
4 changes: 2 additions & 2 deletions tests/Unit/Meta/Runtime/RuntimeMetaTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
use Orisai\ObjectMapper\Args\EmptyArgs;
use Orisai\ObjectMapper\Meta\Runtime\ClassRuntimeMeta;
use Orisai\ObjectMapper\Meta\Runtime\FieldRuntimeMeta;
use Orisai\ObjectMapper\Meta\Runtime\PhpPropertyMeta;
use Orisai\ObjectMapper\Meta\Runtime\RuleRuntimeMeta;
use Orisai\ObjectMapper\Meta\Runtime\RuntimeMeta;
use Orisai\ObjectMapper\Meta\Shared\DefaultValueMeta;
use Orisai\ObjectMapper\Rules\MixedRule;
use PHPUnit\Framework\TestCase;
use ReflectionProperty;
use Tests\Orisai\ObjectMapper\Doubles\NoDefaultsVO;
use function serialize;
use function unserialize;
Expand All @@ -28,7 +28,7 @@ public function test(): void
[],
new RuleRuntimeMeta(MixedRule::class, new EmptyArgs()),
DefaultValueMeta::fromNothing(),
new ReflectionProperty(NoDefaultsVO::class, 'string'),
new PhpPropertyMeta(NoDefaultsVO::class, 'property', true),
),
];

Expand Down

0 comments on commit 5bab92b

Please sign in to comment.