1

I have been recently toying with dynamic PDO connection methods. However I run into some problems when I started to use other classes.

Why can't I connect to database in Admin class with method that has been constructed in Server class?

I have tried many solutions. This one seemed most logical to me ...

How do I make it work so that I wouldn't have to construct connection in every class?

class Server
{
    private $hostdb = 'blah';
    private $namedb = 'blah';
    private $userdb = 'blah';
    private $passdb = 'blah';

    public static $conn;

    public $errorMessage = 'If you read this text, contact web administrator and tell him about your problem.';

    public function __construct()
    {
        $this->connect();
    }

    public function connect()
    {
        try {
            $this->conn = new PDO("mysql:host=$this->hostdb; dbname=$this->namedb", $this->userdb, $this->passdb, array(PDO::ATTR_PERSISTENT => true));
            $this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            $this->conn->exec("SET CHARACTER SET utf8");

        } catch (PDOException $e) {
            echo 'Connection failed: ' . $e->getMessage();
        }
    }
}

And the Admin class:

class Admin extends User
{

    function someFunction($table)
    {
        try {
            $sql = "SELECT * FROM $table";

            //I want to change this line so that my connection would work
            $result = Server::$conn->query($sql);

                        while ($row = $result->fetch(PDO::FETCH_NUM)) {
                            //Do something
                        }
                    } catch (PDOException $e) {
            //Show when debugging
            //echo $e->getMessage();
            echo Server::errorMessage;
        }
    }
}

I have instantiated both Server, User and Admin class in config.req.php file.

When I changed "Server::$conn->" to "static::$conn->" it still gave me an error.

1 Answers1

0

Make sure you have instantiated Server at least once in the Request. Otherwise, connect() will never be called. Also, $this->conn will create a new public instance property. Static properties need to be set with static::$conn or self::$conn.

So change your connect() method to

public function connect()
{
    try {
        self::$conn = new PDO("arguments …"));
        self::$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        self::$conn->exec("SET CHARACTER SET utf8");
        // … shortened for brevity

On a side note, why not just use Dependency Injection? That makes for more maintainable and testable designs, e.g. keep the $this->conn and remove all the static stuff instead (in addition to the constructor) for something like

class Server
{
    private $hostdb = 'blah';
    private $namedb = 'blah';
    private $userdb = 'blah';
    private $passdb = 'blah';

    private $conn;

    public function getConnection() 
    {
        if (!isset($this->conn)) {
            $this->connect();
        }

        return $this->connection;
    }

And then for your Admin class:

class Admin extends User
{
    private $server;

    public function __construct(Server $server)
    {
        $this->server = $server;
    } 

    function someFunction($table)
    {
        try {
            $sql = "SELECT * FROM $table";
            $result = $this->server->getConnection()->query($sql);

On another side note:

$sql = "SELECT * FROM $table"

Interpolating strings into a query makes you open to SQL Injection attacks. Use prepared statements instead.

Community
  • 1
  • 1
Gordon
  • 312,688
  • 75
  • 539
  • 559