所以我在Lynda.com上学习了一个关于高级PHP的教程。他们提到了Late Static Bindings,但我猜他们在制作教程时还没有推出PHP 5.3,所以我正试图弄清楚如何在扩展类中使用"create"函数进行CRUD,并将被调用类的属性拉入函数中。我觉得我错过了一些非常简单的东西,它在我的数据库中插入了一个新行,只是没有内容。这是守则,任何建议都是有用的。
test.PHP文件中的PHP代码。。。
<?php
$user = new User();
$user->username = "johnsmith";
$user->password = "555";
$user->first_name = "john";
$user->last_name = "smith";
$user->create();
?>
扩展DatabaseObject类的用户类。。。
class User extends DatabaseObject {
protected static $table_name="users";
protected static $db_fields = array('id', 'username', 'password', 'first_name', 'last_name');
public $id;
public $username;
public $password;
public $first_name;
public $last_name;
}
具有后期静态绑定的DatabaseObject类。。。
class DatabaseObject {
protected static function attributes() {
$attributes = array();
foreach(static::$db_fields as $field) {
if(property_exists(get_called_class(), $field)) {
$attributes[$field] = get_called_class()->$field;
}
}
return $attributes;
}
protected static function sanitized_attributes() {
global $database;
$clean_attributes = array();
foreach(self::attributes() as $key => $value) {
$clean_attributes[$key] = $database->escape_value($value);
}
return $clean_attributes;
}
public static function create() {
global $database;
$attributes = self::sanitized_attributes();
$sql = "INSERT INTO ".static::$table_name." (";
$sql .= join(",", array_keys($attributes));
$sql .=") VALUES ('";
$sql .= join("', '", array_values($attributes));
$sql .= "')";
if($database->query($sql)) {
static::$id = $database->insert_id();// get last id saved in database and puts it in the id arguement
return true;
} else {
return false;
}
}
实例方法可以访问其属性,类方法(静态方法)不能。所以DatabaseObject中的所有方法都应该是实例方法。例如,
class DatabaseObject {
protected function attributes() {
$attributes = array();
foreach(static::$db_fields as $field) {
if(property_exists(get_called_class(), $field)) {
$attributes[$field] = $this->$field;
}
}
return $attributes;
}
protected function sanitized_attributes() {
global $database;
$clean_attributes = array();
foreach(self::attributes() as $key => $value) {
$clean_attributes[$key] = $database->escape_value($value);
}
return $clean_attributes;
}
public function create() {
global $database;
$attributes = self::sanitized_attributes();
$sql = "INSERT INTO ".static::$table_name." (";
$sql .= join(",", array_keys($attributes));
$sql .=") VALUES ('";
$sql .= join("', '", array_values($attributes));
$sql .= "')";
if($database->query($sql)) {
$this->id = $database->insert_id();// get last id saved in database and puts it in the id arguement
return true;
} else {
return false;
}
}
}
后期静态绑定仅适用于$table_name和$db_fields。
如果要继续使用此结构,您应该将静态字段$db_fields设置为DatabaseObject。否则,将DatabaseObject的类型更改为abstract,为数据库字段设置一个空数组,并将其设置为protected。作为实现DatabaseObject(User)的__construct函数的一部分,使用setFields->array(....)
设置映射字段。或者,您可以允许像$user->foo
这样的直接属性调用,并使用__get
&;__set
魔术方法并预先定义所有允许的字段,而不是使用映射数组。
下面是打印SQL:的DatabaseObject类
class DatabaseObject {
protected static function attributes() {
$attributes = array();
foreach(static::$db_fields as $field) {
if(property_exists(get_called_class(), $field)) {
$attributes[$field] = get_called_class()->$field;
}
}
return $attributes;
}
protected static function sanitized_attributes() {
$clean_attributes = array();
foreach(self::attributes() as $key => $value) {
$clean_attributes[$key] = $value;
}
return $clean_attributes;
}
public static function create() {
$attributes = self::sanitized_attributes();
$sql = "INSERT INTO ".static::$table_name." (";
$sql .= join(",", array_keys($attributes));
$sql .=") VALUES ('";
$sql .= join("', '", array_values($attributes));
$sql .= "')";
print $sql;
}
}
现在,如果我按照你的例子运行这个,我会得到以下输出:
php > $user->create();
PHP Notice: Trying to get property of non-object in php shell code on line 6
PHP Notice: Trying to get property of non-object in php shell code on line 6
PHP Notice: Trying to get property of non-object in php shell code on line 6
PHP Notice: Trying to get property of non-object in php shell code on line 6
PHP Notice: Trying to get property of non-object in php shell code on line 6
INSERT INTO users (id,username,password,first_name,last_name) VALUES ('', '', '', '', '')
这是因为代码不知道静态对象,因为它还没有设置。您可能应该考虑使用动态绑定而不是静态绑定,以获得更好的内存管理和更好的性能。静态绑定在工厂和注册表中很有用,在工厂和注册中心中,您需要维护状态,同时提供对实例的直接访问,而无需实例化注册表类(例如$r = new Registry();$t = $r->get('foo')
);
查看wiki文章http://en.wikipedia.org/wiki/Name_binding
另一个问题是get_called_class()
将返回类的名称,而不是实例。通过将DatabaseObject更改为abstract
,User
实现DatabaseObject
,您可以修改函数的访问权限,并将静态方法更改为非静态方法。
理想情况下,当你使用方法时,它们应该是非静态的,这样在标准OOP编程实践中,A扩展B,$B是B,$B->foo()调用A::foo(
在数据库访问中使用静态绑定有什么原因吗?
编辑--
还想说的是,你不应该把静态代码和非静态代码混合在一起,这是不起作用的,在PHP中也不起作用,当然在任何OOP代码中都不起作用。如果你需要使用静态绑定,你需要使用
- 保留项目的注册表,并将某种引用传递给正在使用的数据库对象
- 保留密钥=>值集的哈希映射
- 将实际的非静态对象传递给处理方法
A::process($b)
,使A::process()
调用$b->$field