PHP使用const / enum而不给它赋值

时间:2013-12-20 12:47:53

标签: php enums

我试图在PHP中部分模仿Enum行为,我也想利用PHP的mixed type

考虑我的代码示例(使用PHP PDO底层):

class DBH {
    /** The current database handler **/
    private $dbh;

    const SQL_NOW = 1;

    public function insert($table, $keyvaluepairs) {
        $sql = "INSERT INTO `{$table}` (";
        $values_sql = ") VALUES(";
        $values = array();
        foreach ($keyvaluepairs as $key => $value) {
            if ($value == SELF::SQL_NOW) {
                $sql .= "NOW(), ";
            }
            else {
                $sql .= "`${key}`, ";
                $values_sql .= "?, ";
                $values[] = $value;
            }
        }
        $query = substr($sql, 0, -2).substr($values_sql, 0, -2).")";
        return $this->query($query, $values);
    }
}

所有$value值都是可能的,只要它们SQL本身允许, PDO不会将自己限制为SQL,它可以进行通信任何RMDMS

据我所知,目前我的SQL_NOW(int)1值发生冲突。

如何确保不会发生价值冲突,如果可能,我可以const / enum 没有值吗?

1 个答案:

答案 0 :(得分:1)

没有值就没有常数,所以任何解决方案都必然涉及“错误”不会或不能使用的值。

一个实际的解决方案是将GUID用于这些常量的值,例如

const SQL_NOW = '{CD90A4D4-47EB-47A0-AFAD-B84944A06507}';

您还需要使用相同的运算符检查此值:

if ($value === SELF::SQL_NOW) { // three equals signs!

由于包含来自网络适配器的唯一MAC地址的信息的GUID无法复制,因此几乎可能发生意外冲突。

那就是说,理论上有人可能会尝试在数据库中插入这个确切的GUID。防止这种情况的唯一方法是使用占位符值,客户端不会意外使用该值。这可以通过对象实例来完成,即

$placeholder = new stdClass;
if ($value === $placeholder) {
    // This test will *never* be true unless someone does $value = $placeholder
}

不幸的是,对象实例不能用作类常量,所以这是不可能的:

const SQL_NOW = new stdClass;

静态属性也无法使用表达式new stdClass进行初始化,因此这也是不可能的:

static $SQL_NOW = new stdClass;

所以这个解决方案只能使用静态方法实现:

private static $SQL_NOW;

public static function SQL_NOW()
{
    return self::$SQL_NOW ?: self::$SQL_NOW = new stdClass;
}

然后,您将在代码中使用函数SQL_NOW()的结果而不是常量SQL_NOW