php - PHP - 有什么方法可以区分 unset 和 null 吗?
问题描述
考虑以下代码:
class Test {
public $definedButNotSet;
}
$Test = new Test();
var_dump($Test->definedButNotSet=== null); // true
var_dump(isset($Test->definedButNotSet)); // false
$Test->definedButNotSet = null;
var_dump(isset($Test->definedButNotSet)); // false
在我看来,PHP 隐式地将定义的变量设置为 null。有什么办法可以规避这一点,并区分明确设置为null
的变量和仅定义但未设置为任何值的变量?
更新:
我基本上想看看在运行时definedButNotSet
变量是否被更新。所以我对以下代码的预期结果是:
$Test = new Test();
var_dump(isset($Test->definedButNotSet)); // false
$Test->definedButNotSet = null;
var_dump(isset($Test->definedButNotSet)); // true expected here but php returns false
差异确实很重要的实际用例,基本上这也是我的用例:更新数据库中的行时,我想更新表的行,用户仅在调用更新方法时才更改。为此,我必须知道,用户是否隐式修改了表示表中行的类中的任何变量。
我正在运行一个自定义 ORM,目前它失败了,如果我在数据库中插入一行,其中一列将 default_timestamp 方法设置为默认值,并且在同一运行时,我尝试再次更新同一行,因为数据库设置值没有反映在我的类实例中,因此在更新时 PHP 向他发送他的值为 null,这是不允许的。
解决方案
稍微挑战一下问题的框架,您要做的是区分对同一属性的两种类型的写入:一种由您的 ORM 自动触发,另一种由用户手动触发。将在插入时提供默认值的值是其中的一个子集,但从数据库检索的值也可能需要与用户提供的值进行不同的处理(例如,跟踪是否需要更新)。
做到这一点的方法是将属性设为私有,并提供 getter 和 setter,或者使用魔法__get
和__set
方法(以及@property
IDE 使用的注释)模拟属性访问器。然后,您可以在初始化代码之外存储已写入哪些属性的映射。
一个简单且可能有问题的实现来显示总体思路:
/**
* This doc-block will be read by IDEs and provide auto-complete
* @property int|null $id
* @property string|null $name
*/
class Test {
private ?int $id = null;
private ?string $name = null;
private array $updatedFields = [];
/**
* @internal Only to be called by the ORM
*/
public function construct(?int $id, ?string $name) {
$this->id = $id;
$this->name = $name;
}
public function __get(string $property) {
if ( property_exists($property, $this) ) {
return $this->$property;
}
else {
throw new LogicError("No such property '$property'");
}
}
public function __set(string $property, $newValue) {
if ( property_exists($property, $this) ) {
$this->$property = $newValue;
$this->updatedFields[ $property ] = true;
}
else {
throw new LogicError("No such property '$property'");
}
}
/**
* Standard meaning of isset() for external code
*/
public function __isset(string $property) {
if ( property_exists($property, $this) ) {
return isset($this->$property);
}
else {
throw new LogicError("No such property '$property'");
}
}
/**
* Special function for ORM code to determine which fields have changed
*/
public function hasBeenWritten(string $property): bool {
if ( property_exists($property, $this) ) {
return $this->updatedFields[ $property ] ?? false;
}
else {
throw new LogicError("No such property '$property'");
}
}
}
推荐阅读
- puppeteer - 在 Ubuntu 上使用 Puppeteer 会显示使用 Ubuntu 的网站吗?
- google-data-studio - Data Studio(Golang RE2):如何将字符串中每个单词的首字母大写
- java - 需要 Retrofi2 Android HTTP 方法注解(例如,@GET、@POST 等)
- java - Java 如何区分单链表和双链表?
- c - char* 数组的隐含衰减是什么?
- java - 这个算法的时间复杂度是多少?
- java - 如果手动完成,则不会调用 CompletableFuture 回调
- deep-learning - 我如何在没有导入错误的情况下运行 Nvidia Digits
- angular - Angular 9 和 .NET Core 应用程序部署在本地 IIS 上的同一文件夹下(找不到此本地主机页面)
- docker - 错误:无法从“/usr/src/app”中找到模块“./build/index.js”