如何区分PHP属性是未定义还是设置为NULL



所以我面临这个问题。我有一个类表示数据库中的一条记录(本例中为User(。类的属性数与数据库表的列数一样多。为了简单起见,我的示例中只有三个:

  1. $id-用户的ID(对于已注册的用户,必须设置为正整数,对于尚未保存在数据库中的用户对象,可能设置为0(
  2. $name-用户名称(必须为每个用户设置,但在从数据库加载之前可能未定义(
  3. $email-用户的电子邮件地址(如果用户没有提交电子邮件地址,则可能为NULL(

我的(简化的(类如下所示:

<?php
class User
{
private $id;
private $name;
private $email;

public function __construct(int $id = 0)
{
if (!empty($id)){ $this->id = $id; }
//If $id === 0, it means that the record represented by this instance isn't saved in the database yet and the property will be filled after calling the save() method
}

public function initialize(string $name = '', $email = '')
{
//If any of the parameters isn't specified, prevent overwriting curent values
if ($name === ''){ $name = $this->name; }
if ($email === ''){ $email = $this->email; }

$this->name = $name;
$this->email = $email;
}

public function load()
{
if (!empty($this->id))
{
//Load name and e-mail from the database and save them into properties
}
}
public function save()
{
if (!empty($this->id))
{
//Update existing user record in the database 
}
else
{
//Insert a new record into the table and set $this->id to the ID of the last inserted row
}
}

public function isFullyLoaded()
{
$properties = get_object_vars($this);
foreach ($properties as $property)
{
if (!isset($property)){ return false; }   //TODO - REPLACE isset() WITH SOMETHING ELSE
}
return true;
}

//Getters like getName() and getId() would come here
}

现在终于解决我的问题了。正如您所看到的,可以在不设置所有属性的情况下创建此类的实例。如果我想调用getName(),而名称还不知道(它不是通过initialize()方法设置的,也没有调用load(((,这就是一个问题。为此,我编写了方法isFullyLoaded(),它检查是否所有属性都是已知的,如果不是,则应该调用load()(来自调用isFullyLoaded()的方法(。问题的核心是,一些变量可能是空字符串("(、零值(0(,甚至是null(如$email属性(。所以我想区分那些有任何值集(包括null(的变量和那些从未被赋值的变量。

具体示例:我想实现这个代码:

$user1 = new User(1);
$user1->initialize('Vic', 'nerd.from.klamath@fallout2.com');
var_dump($user1->isFullyLoaded());
$user2 = new User(2);
$user2->initialize('Cassidy', null); //No e-mail was specified during the registration
var_dump($user2->isFullyLoaded());
$user3 = new User(3);
$user3->initialize('Myron'); //E-mail isn't known yet, but might be saved in the database
var_dump($user3->isFullyLoaded());

输出这个:

bool(true)
bool(true)
bool(false)

TL:DR如何区分未定义的变量和PHP中被赋值为NULL的变量?

这里有另一种引入自定义未定义类(作为singleton(的方法。此外,请确保您的类属性已键入:

class Undefined
{
private static Undefined $instance;
protected function __constructor()
{
}
protected function __clone()
{
}
public function __wakeup()
{
throw new Exception("Not allowed for a singleton.");
}
static function getInstance(): Undefined
{
return self::$instance ?? (self::$instance = new static());
}
}
class Person
{
private int $age;
public function getAge(): int|Undefined
{
return $this->age ?? Undefined::getInstance();
}
}
$person = new Person();
if ($person->getAge() instanceof Undefined) {
// do something
}

但是使用singleton模式也有缺点,因为应用程序中所有未定义的对象将严格相等。否则,每次返回未定义值的get操作都会产生副作用,即另一块分配的RAM。

PHP没有像javascript那样未定义的值。但它不是严格类型的,所以如果你找不到更好的解决方案,这里有一个自定义类型UNDEFINED

<?php
class UNDEFINED { }
class Test {
var $a;
function __construct( $a='' ) {
$this->a = new UNDEFINED();
if( $a !== '' ) {
$this->a = $a;
}
}

function isDefined() {
$result =true;
if(gettype($this->a) === 'object'){
if(get_class($this->a) === 'UNDEFINED') {
$result=false;
}
}
echo gettype($this->a) . get_class($this->a);
return $result;
}
}
$test= new Test();
$test->isDefined();

这里有一个可能更好的版本,它使用instanceof而不是get_call和getType

<?php
class UNDEFINED { }
class Test {
var $id;
var $a;
var $b;
function __construct( $id) {
$this->id = $id;
$this->a = new UNDEFINED();
$this->b = new UNDEFINED();
}
function init( $a = '' , $b = '') {
$this->a = $this->setValue($a,$this->a);
$this->b = $this->setValue($b,$this->b);
}
function setValue($a,$default) {
return $a === '' ? $default : $a;
}
function isUndefined($a) {
return $a instanceof UNDEFINED;
}

public function isFullyLoaded()
{
$result = true;
$properties = get_object_vars($this);
print_r($properties);
foreach ($properties as $property){
$result = $result && !$this->isUndefined($property);
if ( !$result) break;
}
return $result;
}
function printStatus() {
if($this->isFullyLoaded() ) {
echo 'Loaded!';
} else {
echo 'Not loaded';
}
}
}
$test= new Test(1); 
$test->printStatus();
$test->init('hello');
$test->printStatus();
$test->init('', null);
$test->printStatus();

使用property_exists():

<?php
error_reporting(E_ALL);
// oop:
class A {
public $null_var = null;
}
$a = new A;
if(property_exists($a, 'null_var')) {
echo "null_var property existsn";
}
if(property_exists($a, 'unset_var')) {
echo "unset_var property existsn";
}
// procedural:
$null_var = null;
if(array_key_exists('null_var', $GLOBALS)) {
echo "null_var variable existsn";
}
if(array_key_exists('unset_var', $GLOBALS)) {
echo "unset_var variable existsn";
}
// output:
// null_var property exists
// null_var variable exists

最新更新