PHP后期静态绑定问题

时间:2014-04-17 02:43:16

标签: php content-management-system dynamic-programming semantic-markup object-oriented-database

所以我在Lynda.com上关于高级PHP的教程。他们提到了Late Static Bindings,但我认为PHP 5.3在制作教程时并没有出来,所以我试图弄清楚如何使用'创建'函数在扩展类中,并将属性从被调用的类拉入函数中。我觉得我错过了一些非常简单的东西,它在我的数据库中插入了一个新行,只是没有内容。继承代码,任何建议都会有用。

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; 
  }

}

2 个答案:

答案 0 :(得分:1)

如果要继续使用此结构,应该将静态字段$ db_fields设置为DatabaseObject。否则,将DatabaseObject的类型更改为abstract,为数据库fieldset指定一个空数组并将其设置为protected。作为实现DatabaseObject(User)的__construct函数的一部分,请setFields->array(....)设置映射字段。或者,您可以允许直接调用属性$user->foo,并使用__get&amp;&amp; __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更改为abstractUser实现DatabaseObject,您可以修改函数的访问权限,并将静态方法更改为非静态方法,如您所愿。

理想情况下,当您使用方法时,它们应该是非静态的,因此使用标准的OOP编程实践,A扩展B,$ b是B,$ b-&gt; foo()调用A :: foo()其中foo()是A的非静态方法。

您是否有任何理由在数据库访问中使用静态绑定?

编辑 -

另外要说的是,你不应该将静态与非静态代码混合在一起,它只是不起作用,不是在PHP中,当然也不在任何OOP代码中。如果您需要使用静态绑定,则需要

  • 保留项目注册表并传递对您正在使用的数据库对象的某种引用
  • 保留key =&gt;的哈希映射价值集
  • 将实际的非静态对象传递给处理方法A::process($b),以便A::process()调用$b->$field

答案 1 :(得分:1)

实例方法可以访问其属性,类方法(静态方法)不能。 所以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。