我已经从旧的 php 7.4 脚本重新编写了我的代码。我发现我的代码比旧版本更慢 我的旧模型从方法
toArray
导出数据
而他的代表就是这样的
public function toArray()
{
return [
"id" => $this->id;
"name" => $this->name;
//And many other values
]
}
但是现在,使用 PHP 8,我可以使用反射对象来序列化我的对象。 这需要类似:
class MyModel extends Model
{
#[AttributeExport]
private int $id;
#[AttributeExport]
private string $name;
}
//In Model
abstract Model implement JsonSerialize
{
public function jsonSerialize(): array
{
$data = [];
$reflection = new \ReflectionClass(get_called_class());
$elements = array_merge($reflection->getProperties(), $reflection->getMethods());
foreach ($elements as $element) {
$exportableAttributes = $element->getAttributes(
AttributeExport::class,
\ReflectionAttribute::IS_INSTANCEOF
);
foreach ($exportableAttributes as $exportableAttribute) {
/** @var AttributeExport $exportableInstance */
$exportableInstance = $exportableAttribute->newInstance();
$exportName = $exportableInstance->hasName() ? $exportableInstance->getName() : $element->getName();
$method = $element->getName();
if ($element instanceof \ReflectionProperty) {
$method = "get" . ucfirst($method);
}
$data[$exportName] = $this->{$method}();
}
}
return $data;
}
}
我可能错误地认为问题可能出自那里。但你认为在大量数据上,这个策略能产生影响吗?
与旧版本相比,我使用了更多的抽象类,以避免代码重复。不知道是否也会有影响
有两件事需要考虑,您从直接属性访问更改为基于反射的 getter 方法:
看看这个修改,我添加了一个简单的缓存,现在反射方法的运行时间快得多,我认为在大多数设置下性能命中应该是可以接受的:
string(29) "reflection: 0.036892890930176"
string(33) "direct acccess: 0.015763998031616"
string(33) "direct methods: 0.018218040466309"
<?php
#[Attribute]
class AttributeExport
{
public function __construct()
{
}
public function hasName()
{
return false;
}
}
abstract class Model implements JsonSerializable
{
private static $cache = [];
public function jsonSerialize():array
{
$data = [];
if (!isset(self::$cache[self::class]))
{
self::$cache[self::class ] = [];
$reflection = new \ReflectionClass(get_called_class());
$elements = array_merge($reflection->getProperties() , $reflection->getMethods());
foreach ($elements as $element)
{
$exportableAttributes = $element->getAttributes(AttributeExport::class , \ReflectionAttribute::IS_INSTANCEOF);
foreach ($exportableAttributes as $exportableAttribute)
{
/** @var AttributeExport $exportableInstance */
$exportableInstance = $exportableAttribute->newInstance();
$exportName = $exportableInstance->hasName() ? $exportableInstance->getName() : $element->getName();
$method = $element->getName();
if ($element instanceof \ReflectionProperty)
{
$method = "get" . ucfirst($method);
}
self::$cache[self::class][$exportName] = $method;
}
}
}
foreach (self::$cache[self::class] as $exportName => $method)
{
$data[$exportName] = $this->{$method}();
}
return $data;
}
}
class MyModel extends Model
{
public function __construct($id, $name)
{
$this->id = $id;
$this->name = $name;
}
#[AttributeExport]
private int $id;
#[AttributeExport]
private string $name;
public function getId()
{
return $this->id;
}
public function getName()
{
return $this->name;
}
public function toArray()
{
return [
"id" => $this->id,
"name" => $this->name
//And many other values
];
}
public function toArrayMethods()
{
return [
"id" => $this->getId(),
"name" => $this->getName()
//And many other values
];
}
}
$z = new MyModel(1, "a");
$zr = $z->jsonSerialize();
$zr2 = $z->toArray();
$time1 = microtime(true);
for ($a = 0;$a < 100000;$a++)
{
$x = new MyModel(1, "a");
$r = $x->jsonSerialize();
}
$timea = microtime(true) - $time1;
$time2 = microtime(true);
for ($b = 1;$b < 100000;$b++)
{
$x2 = new MyModel(1, "a");
$r2 = $x2->toArray();
}
$timeb = microtime(true) - $time2;
$time3 = microtime(true);
for ($b = 1;$b < 100000;$b++)
{
$x2 = new MyModel(1, "a");
$r2 = $x2->toArrayMethods();
}
$timec = microtime(true) - $time3;
var_dump("reflection: " . $timea);
var_dump("direct acccess: " . $timeb);
var_dump("direct methods: " . $timec);
也可以使用反射来访问没有 getter 的属性。