4

I'm kinda new to PDO with MYSQL, here are my two files:

I have a connection class that I use to connect to the database:

class connection{

private $host = 'localhost';
private $dbname = 'devac';
private $username = 'root';
private $password ='';  

public $con = '';

function __construct(){

    $this->connect();   

}

function connect(){

    try{

        $this->con = new PDO("mysql:host=$this->host;dbname=$this->dbname",$this->username, $this->password);
        $this->con->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);


    }catch(PDOException $e){

        echo 'We\'re sorry but there was an error while trying to connect to the database';
        file_put_contents('connection.errors.txt', $e->getMessage().PHP_EOL,FILE_APPEND);

    }
}   
}

I have an account_info class that i use to query the data from the database:

class account_info{


function getAccountInfo(){

    $acc_info = $this->con->prepare("SELECT * FROM account_info");
    $acc_info->execute();

    $results = $acc_info->fetchAll(PDO::FETCH_OBJ);

    foreach ($results as $key) {
        $results->owner_firstname;

    }
}       


}

I include both these files in my index.php page:

include_once 'classes/connection.class.php';
include_once 'classes/accountinfo.class.php';

$con = new connection();
$info = new account_info();
$info->getAccountInfo();

I just cant get it to work I'm not getting any output, I think it has something to do with the scope, but I don't know the correct why to fix it as I'm new to this PDO and OOP stuff. Thanks in advance.

Roger Williams
  • 159
  • 2
  • 6
  • 14

2 Answers2

10

Solution 1

Replace class account_info { with class account_info extends connection {

Replace

$con = new connection();
$info = new account_info();

with

$info = new account_info();

and it should work.

Solution 2 (suggested)

I highly suggest you to solve your problem with dependency injection in this case. Just replace your account class with:

class account_info {

    private $con;

    public function __construct(connection $con) {
        $this->con = $con->con;
    }

    public function getAccountInfo(){

        $acc_info = $this->con->prepare("SELECT * FROM account_info");
        $acc_info->execute();

        $results = $acc_info->fetchAll(PDO::FETCH_OBJ);

        foreach ($results as $key) {
            $results->owner_firstname;
        }
    }       

}

and use it in index.php like this:

include_once 'classes/connection.class.php';
include_once 'classes/accountinfo.class.php';

$con = new connection();
$info = new account_info($con);
$info->getAccountInfo();

Explanation

As a general good rule: always specify the scope keyword for functions (public, protected or private).

The first solution is called inheritance and what we basically did was extending the account class with the connection class in order to inherit all the methods and properties from the connection class and easily use them. In this case you have to watch out for naming conflicts. I suggest you to take a look at the class inheritance in the PHP manual.

The second solution is called dependency injection and it is a wildly encouraged design pattern that makes your classes accept other classes in their constructor in order to explicitly define the class dependency tree (in this case account depend from connection and without the connection we can't make account work).

Another, of thousands of possible solution, would be the one that someone posted below which is a design pattern called Singleton. However that patter has been reevaluated recently as anti-pattern and should not be used.

Shoe
  • 70,092
  • 30
  • 150
  • 251
  • So then he's going to create a new database connection for every instance of his account class (and every other class which requires a database connection). – Martin Jul 16 '12 at 23:49
  • Ok so following the latest revision he now needs to keep track of $con throughout the scope of his application (and be very careful not to overwrite it), and pass it to every other object/closure explicitly. Now I see why singletons are such a bad idea! :) – Martin Jul 16 '12 at 23:58
  • @Martin, singletons uses the global scope of the static keyword in order to have a free-to-use globally class instance and in order to have a single instance. But it's an hack that is not needed in a well structured application. It's called anti-pattern because it's not a pattern at all and goes against few of the most important points of the design pattern guideline. – Shoe Jul 17 '12 at 00:01
  • Dependency injection is surely the way to go. – Shoe Jul 17 '12 at 00:02
  • Thank you! the first solution worked great! but I really want to use the second solution but I get this error: Fatal error: Call to undefined method connection::prepare() in C:\wamp\www\php-tests\projects\devac\classes\accountinfo.class.php on line 13 – Roger Williams Jul 17 '12 at 00:24
7

A common method is to use a singleton pattern in your database class.

Something like this:

class connection {

   private static $hInstance;

   public static function getInstance() {
     if (!(self::$hInstance instanceof self)) {
         self::$hInstance = new self();
     }

     return self::$hInstance;
   }

   /* your code */
}

Then, you can simply use

$database = connection::getInstance(); 
$database->con->prepare(....)

etc

Martin
  • 6,362
  • 4
  • 21
  • 28
  • Singletons are highly discouraged nowadays. – Shoe Jul 16 '12 at 23:47
  • I think internet is full of this kind of articles – Shoe Jul 17 '12 at 00:00
  • I can post links to the contrary all day long: http://c2.com/cgi/wiki?SingletonsAreGood - it's more about usage than the pattern itself. And it certainly is a simpler, cleaner solution for the OP. – Martin Jul 17 '12 at 00:03
  • 2
    Paraphrased from Brian Button: 1) They are generally used as a global instance, why is that so bad? Because you hide the dependencies of your application in your code, instead of exposing them through the interfaces. Making something global to avoid passing it around is a code smell. 2 ) They violate the Single Responsibility Principle: by virtue of the fact that they control their own creation and lifecycle. – Shoe Jul 17 '12 at 00:06
  • 3) They carry state around for the lifetime of the app. Another hit to testing since you can end up with a situation where tests need to be ordered which is a big no no for unit tests. Why? Because each unit test should be independent from the other. – Shoe Jul 17 '12 at 00:06
  • These are just 3 of the points i like more. Tell me all about it. I'm at open ears. – Shoe Jul 17 '12 at 00:06
  • @Jeffrey i'd appreciate it if you could stop spamming my inbox :) you're entitled to your own answer, keep it there. – Martin Jul 17 '12 at 00:08
  • thanks for the answer, but I'll go with the Dependency injection! :) – Roger Williams Jul 17 '12 at 00:41
  • @RogerWilliams no problem! Just for the record, in your usage $con is in a global scope anyway so it's exactly the same just a messier way of achieving it. Also, you need to explicitly pass it to any new object or closure. Final note, if you even rename the $con variable in your connection class you need to update all of your other objects too :) – Martin Jul 17 '12 at 00:46