PHP PDO:我们应该将pdo的`function __construct`设置为`private`还是`public`?

时间:2013-08-05 10:29:41

标签: php pdo php-5.3 public-method

我们应该将pdo的function __construct设置为private还是public?如果我将其设置为public

,它是否会成为漏洞的主题

这是我的db类,

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)

1 个答案:

答案 0 :(得分:7)

没有。你在考虑这个错误。您的公共方法是您向其他使用您的类的开发人员提供的API。

在编写课程结束时,想象一下,您正在将文档交给另一位开发人员。您将列出其他开发人员可以使用的“端点”。目前这些是:

  • __construct()
  • connection()

显然,您希望connection()更像connect(),因为对于查看代码的其他开发人员而言,它更有意义。即使makeConnection()更好。

单身人士很不可能

将构造函数设置为private通常是出于以下原因:单例。你想要避免全球状态,单身等等 - 他们是不好的做法,让测试变得更加艰难。

  

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

阅读 this post ,深入了解为什么单身人士只是愚蠢。如果您不想要多个连接实例,不创建一个。如果你不能创建一个,那么你需要重新考虑你的架构(这不应该太糟糕,因为处理数据库的东西通常是在你正在做的任何事情的早期阶段。)

最后,您的构造函数需要 public 。为什么?因此,使用它的开发人员(想象自己是另一个开发人员)可以将其用于预期目的。


额外说明:

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

  2. 不要从构造函数中调用$this->connection()。如果你这样做的话,你可以把它全部推到那里。相反,请致电:

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

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