grifart/not-serializable

明确指出该类不适用于序列化。

dev-master 2022-03-30 19:20 UTC

This package is auto-updated.

Last update: 2024-08-29 05:37:38 UTC


README

...这个包使您更容易实现。

一个故事

2022年3月发生了这件事。

class UserId { 
   private int $id;
   public function __construct(int $id) {$this->id = $id}
}

// later in an app
$userId = new UserId(42);
// ...
$_SESSION['user_id'] = $userId;

这将起作用。没有警告,没有错误,没有问题。现在...

...

一年后,您决定对UserId对象进行内部更改——将私有属性$id重命名为$identifier

class UserId { 
-   private int $id;
+   private int $identifier;
    public function __construct(int $id) {
-        $this->id = $id
+        $this->identifier = $id
    }
}

没有行为变化。外部观察者不应该能够找到对象行为的任何变化。静态分析通过,测试通过。一切顺利!您部署了您的应用程序。

砰!🔥 每个已经登录的用户在会话反序列化时都会导致应用程序硬崩溃。这是因为隐式序列化使私有属性公开了公共接口。

摘要

隐式序列化支持是一个爆炸性陷阱 💥,您无法从表面上或甚至在代码审查中轻松地发现。您必须检查整个对象生命周期,包括代码历史。几乎不可能发现。

这与禁用未明确设计为扩展的对象的继承支持非常相似——默认为final。您可以在12中找到很好的理由。

TL;DR: 您可以获得更好的对象封装,您确切地知道您的对象是如何工作的。

解决方案

👉 用显式序列化替换隐式序列化。

1. 禁用隐式序列化

在PHP中,每个对象默认都是可序列化的,直到您明确表示否则。所以,让我们明确表示。

这对于值对象及其所有衍生品(如实体)来说最有意义。但是,禁用所有类的序列化支持并没有坏处,因为您永远不希望序列化一个服务。

打开您的PhpStorm设置,然后转到Editor > File and Code Templates > Files > PHP Class并更新模板。

final class ${NAME} {
	use \Grifart\NotSerializable\NoSerialization;
}

PhpStorm default template settings

使用Composer在项目中使用此包

composer require grifart/not-serializable

它包含一个简单的特质,该特质禁用了PHP >7.4的序列化支持。这是因为序列化API已经发生了变化php-watch

2. 显式实现序列化

当您需要序列化支持时,明确实现序列化API。

好事是,当默认情况下无法序列化时,有人必须做出决定,即我们需要它可序列化

这还允许我们选择正确的序列化类型

a) 短期 & 简单

PHP序列化API:允许您快速开始。当您开始移动您的类时(严重依赖于我们的类的FQNs)会出错。

您可以通过以下方式走这条路:

  1. 移除特质
  2. 实现__serialize()__unserialize()方法。

b) 长期序列化

grifart/stateful:提供严格的版本控制、字段检查和FQN路由。设计用于

  • 序列化可以在多年后反序列化的情况(例如不可变事件流)
  • 当代码库发生重大变化时
  • 为了最大限度的严格性,因此它会在您的开发机器上失败,而不是在生产环境中。

您可以通过以下方式走这条路:

  1. 移除特质
  2. 实现Stateful接口并使用composer requiregrifart/stateful

进一步开发

  • PhpStan / Rector 规则,用于查找/修复没有启用序列化且未显式实现序列化的类(如何仅应用于值对象及其派生类?)