PHP 中的链接方法


Chaining methods in PHP

$db->select("users")->where(array("username", "=", "username"));
$db->update("users", array("username" => "username", "password" => "12345"))->where(array("id", "=", "14"));

好的,我想通过将where((方法链接到选择,更新和删除来编写像上面这样的语句。我的问题是;如何确定我是否在 where 之前使用了选择、更新或删除,以便我可以将正确的值绑定到正确的语句上。

我想要这样的东西:

public function where() {
    if($this->select()) { 
        // so if $db->select("users")->where(array("username", "=", "username"));
        // save the where data in the select variable.
    }
    elseif($this->update()) {
        // so if $db->update("users", array("username" => "username", "password" => "12345"))->where(array("id", "=", "14"));
        // save the where data in the update variable.
    }
    elseif($this->delete()) {
        // so if $db->delete("users")->where(array("username", "=", "username"));
        // save the where data in the delete variable.
    }
}

但是上面的代码当然是无效的,而且我没有使用任何框架。

public function select($table, $what = null) {
    $what == null ? $what = "*" : $what;
    $this->_select = "SELECT {$what} FROM {$table}";
        return $this;
}

您必须保持该状态。这不是要判断之前的电话是select()还是update(),这是思考问题的错误方式。你只需要select/update/delete中的每一个来修改$this,这样$this,总是知道它正在构建什么样的查询。

一个死的简单例子:

public function select() {
  $this->kind == 'select';
  return $this;
} 
public function where() {
  if ($this->kind == 'select') {
    ...
  return $this;
}

链式方法共享的唯一内容是它们各自返回$this,以便后续方法可以链接到末尾。这一切都是关于在$this中存储状态,直到某个最终方法调用实际评估建立的查询。

像这样:

public function select($table, $fields = '*')
{
    $this->query = "SELECT {$fields} FROM `{$table}`";
    return $this;
}
public function where($conditions = [])
{
    if ($this->query)
    {
        if ($conditions)
        {
            foreach ($conditions as $key => &$val)
                $val = "`{$key}` = '{$val}'";
            $this->query .= ' WHERE ' . implode(' AND ', $conditions);
        }
        $db->query($this->query);
        $this->query = '';
        return $this;
    }
}

这将起作用,但是,您必须注意,此结构将允许您执行以下操作:

$db->where();

这是完全有效的,即使直接在数据库中调用where()也没有意义。

此外,不需要 WHERE 子句的查询不会运行,因为只有where()实际进行调用。

如何解决这个问题?

我们实际上可以使用一个非常有趣的 OOP 机制:析构函数方法。PHP 在对象不再使用后立即销毁它们,我们可以在这里探索此功能作为运行查询的触发器。我们只需要将查询分离到一个新对象。

class dbQuery
{
    private $db;
    private $conditions = [];
    function where($conditions = [])
    {
        $this->conditions = array_merge($this->conditions, $conditions);
        return $this;
    }
    function __construct($db, $query)
    {
        $this->db = $db;
        $this->query  = $query;
    }
    function __destruct()
    {
        if ($this->conditions)
        {
            foreach ($this->conditions as $key => &$val)
                $val = "`{$key}` = '{$val}'";
            $this->query .= ' WHERE ' . implode(' AND ', $this->conditions);
        }
        $this->db->result = $db->query($this->query);
    }
}
class Database
{
    public $result = null;
    protected static $instance;
    function __construct()
    {
        if (!self::$instance)
            self::$instance = new mysqli('localhost', 'user', 'password', 'dbname');
    }
    public function query($query)
    {
        return self::$instance->query($query);
    }
    public function select($table, $fields = '*')
    {
        return new dbQuery($this, "SELECT {$fields} FROM `{$table}`");
    }
}

这样$db->where()就不起作用,因为它不存在,使用 $db->select('table')$db->select('table')->where([...]) 都会给出结果,甚至允许扩展语法以多次使用 where(),例如:

$db->select('table')->where(['id' => 100])->where(['price' => 1.99]);