PHP PDO:我们应该设置PDO';将“function __construct”转换为“private”或“p


PHP PDO: Should we set pdo's `function __construct` to `private` or `public`?

我们应该将pdo的function __construct设置为private还是public?如果我将其设置为public,它会成为漏洞的主题吗?

这是我的数据库类

class pdo_connection
{
    public $connection; // handle of the db connexion

    public function __construct($dsn = 'mysql:host=localhost;dbname=xxx_2013',$username = 'root',$password = 'xxx')
    {   
    $this->dsn = $dsn;
        $this->username = $username;
        $this->password = $password;
        $this->connection();
    }

    private function connection()
    {
        try
        {
            $this->connection = new PDO($this->dsn, $this->username, $this->password, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
            $this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 
        }
        catch (PDOException $e) 
        {
            # call the get_error function
            $this->get_error($e);
        }
        // return $this->connection;
    }
...
}

编辑:

class database extends common
{
    /**
     * Set the class property.
     */
    protected $connection = null;
    protected $dsn,$username,$password;
    /**
     * Set the class contructor.
     * @reference: http://us.php.net/manual/en/language.oop5.magic.php#object.sleep
     */
    public function __construct($dsn,$username,$password)
    {
        $this->dsn = $dsn;
        $this->username = $username;
        $this->password = $password;
        //$this->connect();

    }
    /**
     * make the pdo connection.
     * @return object $connection
     */
    public function connect()
    {
        try
        {
            # MySQL with PDO_MYSQL  
            # To deal with special characters and Chinese character, add charset=UTF-8 in $dsn and array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8").
            $this->connection = new PDO($this->dsn, $this->username, $this->password, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
            $this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 
        }
        catch (PDOException $e) 
        {
            # call the get_error function
            $this->get_error($e);
        }
    }
    /**
     * get the number of rows in a result as a value string.
     * @param string $query
     * @param array $params
     * @return number
     */
    public function num_rows($query, $params = array())
    {
        try 
        {
            # create a prepared statement
            $stmt = $this->connection->prepare($query);
            # if $params is not an array, let's make it array with one value of former $params
            if (!is_array($params)) $params = array($params);
            # execute the query
            $stmt->execute($params);
            # return the result
            return $stmt->rowCount();
        } 
        catch (PDOException $e) 
        {
            # call the get_error function
            $this->get_error($e);
        }
    }
    /**
     * fetch a single row of result as an array ( =  one dimensional array).
     * @param string $query
     * @param array $params
     * @param boolean $array_to_object
     * @return object/ array
     */
    public function fetch_assoc($query, $params = array(), $array_to_object = true)
    {
        try
        {
            # prepare the query
            $stmt = $this->connection->prepare($query);
            # if $params is not an array, let's make it array with one value of former $params
            if (!is_array($params)) $params = array($params);
            # the line
            //$params = is_array($params) ? $params : array($params);
            # is simply checking if the $params variable is an array, and if so, it creates an array with the original $params value as its only element, and assigns the array to $params.
            # This would allow you to provide a single variable to the query method, or an array of variables if the query has multiple placeholders.
            # The reason it doesn't use bindParam is because the values are being passed to the execute() method. With PDO you have multiple methods available for binding data to placeholders:
            # bindParam
            # bindValue
            # execute($values)
            # The big advantage for the bindParam method is if you are looping over an array of data, you can call bindParam once, to bind the placeholder to a specific variable name (even if that variable isn't defined yet) and it will get the current value of the specified variable each time the statement is executed.
            # execute the query
            $stmt->execute($params);
            # return the result
            if($array_to_object) return parent::array_to_object($stmt->fetch());
                else return $stmt->fetch();
        }
        catch (PDOException $e) 
        {
            # call the get_error function.
            $this->get_error($e);
        }
        /*
        or,
        catch (Exception $e)
        {
            // Echo the error or Re-throw it to catch it higher up where you have more
            // information on where it occurred in your program.
            // e.g echo 'Error: ' . $e->getMessage(); 
            throw new Exception(
                __METHOD__ . 'Exception Raised for sql: ' . var_export($sql, true) .
                ' Params: ' . var_export($params, true) .
                ' Error_Info: ' . var_export($this->errorInfo(), true),
                0,
                $e);
        }
        */
    }
    /**
     * fetch a multiple rows of result as a nested array ( = multi-dimensional array).
     * @param string $query
     * @param array $params
     * @param boolean $array_to_object
     * @return object/ array
     */
    public function fetch_all($query, $params = array(), $array_to_object = true)
    {
        try
        {
            # prepare the query
            $stmt = $this->connection->prepare($query);
            # if $params is not an array, let's make it array with one value of former $params
            if (!is_array($params)) $params = array($params);
            # when passing an array of params to execute for a PDO statement, all values are treated as PDO::PARAM_STR.
            # use bindParam to tell PDO that you're using INTs
            # wrap the bindParam function in a foreach that scan your parameters array
            # it's $key + 1 because arrays in PHP are zero-indexed, but bindParam wants the 1st parameter to be 1, not 0 (and so on).
            /*
            foreach($params as $key => $param)
            {
              if(is_int($param))
                {
                    $stmt->bindParam($key + 1, $param, PDO::PARAM_INT);
                }
              else
                {
                    $stmt->bindParam($key + 1, $param, PDO::PARAM_STR);
                }
            }
            # execute the query
            $stmt->execute();
            */
            # execute the query
            $stmt->execute($params);
            # return the result
            if($array_to_object) return parent::array_to_object($stmt->fetchAll(PDO::FETCH_ASSOC));
                else return $stmt->fetchAll(PDO::FETCH_ASSOC);
        }
        catch (PDOException $e) 
        {
            # call the get_error function
            $this->get_error($e);
        }
    }
    /**
     * return the current row of a result set as an object.
     * @param string $query
     * @param array $params
     * @return object
     */
    public function fetch_object($query, $params = array())
    {
        try
        {
            # prepare the query
            $stmt = $this->connection->prepare($query);
            # if $params is not an array, let's make it array with one value of former $params
            if (!is_array($params)) $params = array($params);
            # execute the query
            $stmt->execute($params);
            # return the result
            return $stmt->fetchObject();
            //return $stmt->fetch(PDO::FETCH_OBJ);
        }
        catch (PDOException $e) 
        {
            # call the get_error function
            $this->get_error($e);
        }
    }
    /**
     * insert or update data.
     * @param string $query
     * @param array $params
     * @return boolean - true.
     */
    public function run_query($query, $params = array())
    {
        try
        {
            $stmt = $this->connection->prepare($query);
            $params = is_array($params) ? $params : array($params);
            $stmt->execute($params);
            return true;
        }
        catch (PDOException $e) 
        {
            # call the get_error function
            $this->get_error($e);
        }
    }
    /**
     * with __sleep, you return an array of properties you want to serialize. the point is to be able to exclude properties that are not serializable. eg: your connection property.
     * @return array
     */
    public function __sleep()
    {
        return array('dsn', 'username', 'password');
    }
    /**
     * the intended use of __wakeup() is to reestablish any database connections that may have been lost during serialization and perform other reinitialization tasks.
     */
    public function __wakeup()
    {
        $this->connect();
        //$this->connection =  new PDO($this->dsn, $this->username, $this->password, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
        //$this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    }
    /**
     * display error.
     * @return string
     */
    public function get_error($e) 
    {
        $this->connection = null;
        die($e->getMessage());
    }
    /**
     * close the database connection when object is destroyed.
     */
    public function __destruct()
    {
        # set the handler to NULL closes the connection propperly
        $this->connection = null;
    }
}

用法:

$database = new database(DSN,DB_USER,DB_PASS);
$connection = $database->connect();
var_dump($connection);

结果,

null

应该是

object(database)[1]
  protected 'connection' => 
    object(PDO)[2]
  protected 'dsn' => string 'mysql:host=localhost;dbname=xxx_2013' (length=42)
  protected 'username' => string 'xxx' (length=4)
  protected 'password' => string 'xxx' (length=5)

否。你想错了。您的公共方法是您提供给使用您的类的其他开发人员的API。

在编写完您的类之后,想象一下您正在将文档交给另一个开发人员。您将列出其他开发人员可以使用的"端点"。目前有:

  • __construct()
  • connection()

很明显,您希望connection()更像connect(),因为它对另一个查看代码的开发人员来说更有意义。即使是makeConnection()也更好。

光棍是坏的

将构造函数设置为private通常是出于以下原因:singleton。你想避免全局状态、单身等——这是一种糟糕的做法,会让测试变得更加困难。

在对象位于共享内存中的语言中,Singleton可以用于保持较低的内存使用率。您不创建两个对象,而是从全局共享的应用程序内存中引用一个现有实例。在PHP中没有这样的应用程序内存。在一个请求中创建的Singleton正是为该请求而存在的。在同时完成的另一个请求中创建的Singleton仍然是一个完全不同的实例。因此,辛格尔顿的两个主要目的之一在这里不适用。

阅读这篇文章,深入了解单身汉为什么愚蠢。如果不需要多个连接实例,请不要创建一个。如果你忍不住要创建一个,那么你需要重新思考你的体系结构(这应该不会太糟糕,因为处理DB的东西通常处于你正在做的任何事情的早期阶段)。

在结束时,构造函数需要是公共。为什么?因此,使用它的开发人员(将自己想象成另一个开发人员)可以将它用于预期目的。


额外注释:

  1. 你的用户名/密码不应该硬编码到类构造函数中,你应该在创建对象时传递这些。

  2. 不要从构造函数中调用$this->connection()。如果你这样做的话,你还不如把它都塞进去。相反,请致电:

    $db = new pdo_connection($username, $password, $etc);
    $db->connection();

这意味着您可以将对象传递到任何您喜欢的地方,但您只在运行connection()方法时使用资源(创建连接)。