考虑以下代码:
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
Run Code Online (Sandbox Code Playgroud)
在我看来,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
Run Code Online (Sandbox Code Playgroud)
一个实际用例,其中差异确实很重要,基本上这也是我的用例:更新数据库中的行时,我想更新表的行,用户仅在调用更新方法时更改。为此,我必须知道,用户是否隐式修改了表示表中行的类中的任何变量。
我正在运行一个自定义 ORM,目前它失败了,如果我在数据库中插入一行并将 default_timestamp 方法设置为默认值的列,并且在同一个运行时,我尝试再次更新同一行,由于数据库设置值没有反映在我的类实例中,因此在更新时 PHP 发送给他的值为 null,这是不允许的。
为了挑战问题的框架,稍微,您想要做的是区分对同一属性的两种类型的写入:由 ORM 自动触发的写入和由用户手动触发的写入。将在插入时提供默认值的值是其中的一个子集,但是从数据库检索的值也可能需要以不同于用户提供的值的方式进行处理(例如,跟踪是否需要更新)。
实现此目的的方法是将属性设置为private,并提供 getter 和 setter,或者使用 magic__get和__setmethods(以及@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'");
}
}
}
Run Code Online (Sandbox Code Playgroud)