为每个方法调用处理声明文件中的 PHP 个对象

Handle PHP objects on declaration file for every method call

我正在寻找一种方法来构建处理程序或编辑 php 对象,以下是 mysqli 的示例

我的系统有很多文件,在变量中使用 mysqli 对象

$my_var=new mysqli($host, $user, $pass, $base);

Files 调用它进行查询并得到如下结果:

$q=$my_var->query("SELECT * FROM table");
$q->fetch_assoc();

如果查询出错,$my_var->error 将填充在第一行,并在第二行抛出错误 500。

我正在寻找一种方法来为 $my_var->error 构建处理程序并在调用任何 fetch_* 方法之前抛出错误,因此,

有什么方法可以为 $my_var->error 构建 handler/listener 吗?

如果这不可能,有什么方法可以覆盖 mysqli fetch_assoc()、fetch_row() 和 fetch_array() 方法来检查 $my_var->error 是否为真并在继续之前显示错误?

我知道 try{}catch()throw new Exceptionor die() 方法,但这些方法意味着要编辑系统中的每个 fetch_*,我只想编辑连接文件.

谢谢!

---编辑中---

我认为准备好的语句不是我要找的。

---编辑2---

不,我不是在寻找如何获取 mysqli 错误。

感谢fyrye的帮助!

---回答最终代码---

class mysqli2{
    private $c;
    function __construct(...$args){ // open connection
        $this->c=new mysqli(...$args);
        if(!empty($this->c->error)){ // check for errors
            echo("<script>console.error(\"MySQL: ".$this->c->error."\");</script>");
        }
    }
    function query($query, $resultmode = MYSQLI_STORE_RESULT){
        $r=$this->c->query($query, $resultmode); // make query
        if(!empty($this->c->error)){ // check for errors
            echo("<script>console.error(\"MySQL: ".$this->c->error."\");</script>");
        }
        return $r; // returns query results
    }
    function __call($method, $args){ // calls others mysqli methods
        return $this->c->$method(...$args);
    }
    function __get($name){ // get all the properties
        return $this->c->$name;
    }
    function __set($name, $value){ // set all the properties
        if (property_exists($this->c, $name))$this->c->$name = $value;
    }
}

为了提出最佳实践,在使用 PDO 或 MySQLi 扩展时,建议始终检查任何可用方法的 return 结果,然后再继续使用依赖其结果的方法.

As mysqli::query returns false on an error,在使用fetch_assoc之前应该检查它,而不是假设它不是false。这同样适用于使用 fetch_assoc,因为它可以 return NULL;

if (!$q = $my_var->query($sql)) {
    //something went wrong - handle the error here.
}
if ($data = $q->fetch_assoc()) {
   echo $data['column'];
}

然而,正如我所建议的,您需要创建一个抽象层。

由于 $q 出错时会是 false,因此您问题中代码的异常是:

Fatal error: Call to a member function fetch_assoc() on boolean

意味着您将无法重写 fetch_* 方法,而不重写 mysqli::query 以始终 return 一个对象。

请不要在生产代码中使用。

这只是一个示例,说明如何用您自己的方法覆盖 mysqli::query 方法。您还需要覆盖所有其他 mysqli::*** methods,例如 preparecommit

示例https://3v4l.org/PlZEs

class Conn
{

    private $conn;

    public function __construct(...$args) 
    {
        $this->conn = new mysqli(...$args);
    }

    public function query($query, $resultmode = \MYSQLI_STORE_RESULT) 
    {
       $d = $this->conn->query($query, $resultmode);
       if (!empty($this->conn->error)) {
           throw new \RuntimeException($this->conn->error);
       }

       return $d;
    }
}

//Your connection code
$con = 'my_var';
$$con = new Conn('host', 'user', 'pass', 'base');

//example usage of valid query
$q = $my_var->query('Valid Query');
$q->fetch_assoc();

//example use of invalid query throwing an exception before `fetch_assoc`
$q = $my_var->query('This is not valid');
$q->fetch_assoc();

结果

I was successful
-----

Fatal error: Uncaught exception 'RuntimeException' with message 'Expected "Valid Query"' in /in/PlZEs:51
Stack trace:
#0 /in/PlZEs(70): Conn->query('This is not val...')
#1 {main}
  thrown in /in/PlZEs on line 51

此方法使用 PHP 5.6 argument packing and unpacking 来匹配函数调用参数,以避免必须手动定义它们。

可以对此进行扩展以将消息写入日志文件、发送电子邮件、触发事件或显示友好的错误消息而不是抛出异常。以及用您自己的 Statement 对象覆盖 mysqli_stmt 响应。