我试图在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
没有值吗?
答案 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
。