7

from http://www.php.net/manual/en/class.pdo.php

###### config.ini ######
db_driver=mysql
db_user=root
db_password=924892xp

[dsn]
host=localhost
port=3306
dbname=localhost

[db_options]
PDO::MYSQL_ATTR_INIT_COMMAND=set names utf8

[db_attributes]
ATTR_ERRMODE=ERRMODE_EXCEPTION
############

<?php class Database {
    private static $link = null ;

    private static function getLink ( ) {
        if ( self :: $link ) {
            return self :: $link ;
        }

        $ini = _BASE_DIR . "config.ini" ;
        $parse = parse_ini_file ( $ini , true ) ;

        $driver = $parse [ "db_driver" ] ;
        $dsn = "${driver}:" ;
        $user = $parse [ "db_user" ] ;
        $password = $parse [ "db_password" ] ;
        $options = $parse [ "db_options" ] ;
        $attributes = $parse [ "db_attributes" ] ;

        foreach ( $parse [ "dsn" ] as $k => $v ) {
            $dsn .= "${k}=${v};" ;
        }

        self :: $link = new PDO ( $dsn, $user, $password, $options ) ;

        foreach ( $attributes as $k => $v ) {
            self :: $link -> setAttribute ( constant ( "PDO::{$k}" )
                , constant ( "PDO::{$v}" ) ) ;
        }

        return self :: $link ;
    }

    public static function __callStatic ( $name, $args ) {
        $callback = array ( self :: getLink ( ), $name ) ;
        return call_user_func_array ( $callback , $args ) ;
    }
} ?>

<?php // examples
$stmt = Database :: prepare ( "SELECT 'something' ;" ) ;
$stmt -> execute ( ) ;
var_dump ( $stmt -> fetchAll ( ) ) ;
$stmt -> closeCursor ( ) ;
?>

My questions are:

What is singleton?

What does static mean/do?

What is public static function __callStatic ( used for?

And how can I make it, that PDO only connects to the database when needed? Such as a query or escaping? So if the class/object is unused then it doesn't connect.

Garis M Suero
  • 7,974
  • 7
  • 45
  • 68
Johnny
  • 1,963
  • 4
  • 21
  • 24
  • 2
    Singletons have been subject to a lot of criticism over the years and you should avoid them if possible. This is especially true in environments where all objects live only for the Request. Have a look around SO for more info. – Gordon Sep 15 '10 at 07:16
  • @gordon: Singletons are not(!) a bad solution in general. They are very useful for example for front-controllers, request-objects, etc. But I also heart that it's not recommended for using with database-objects. But you can't say "just avoid them", I think. It's a common design-pattern and very useful. – Fidi Sep 15 '10 at 07:39
  • 1
    @faileN Singletons are(!) a bad solution in general. Even [Erich Gamma says that nowadays](http://www.informit.com/articles/printerfriendly.aspx?p=1404056). I won't go deeper into this as this has been sufficiently explained elsewhere. Like I said, [have a look around](http://stackoverflow.com/search?q=singleton+php) – Gordon Sep 15 '10 at 07:58
  • 2
    @Gordon: thanks for the link. Quite interesting :) – Fidi Sep 15 '10 at 14:57

5 Answers5

4

A singleton is a software design pattern that restricts the initiation of a class to one instance. http://en.wikipedia.org/wiki/Singleton_pattern

Static means that something belongs to the class and not a particular instance. In PHP, this also means that a static method needs to be called with :: not ->

_callStatic returns the PDO link if it has already been established. Otherwise, it first creates the link and then returns it.

The answer to your fourth question is precisely the singleton pattern. It ensures that the connection is only set up once, when needed.

brian_d
  • 11,190
  • 5
  • 47
  • 72
  • A *possible* answer to the fourth question is the use of the singleton pattern. There are other ways (e.g. connecting lazily). – strager Sep 15 '10 at 06:31
  • Why does __callStatic need call_user_func_array? – Johnny Sep 15 '10 at 06:39
  • @Johnny, This `__callStatic` is acting as a proxy to `self::getLink()->name`. When you call `Database::query`, it is translated into `Database::getLink()->query`. – strager Sep 15 '10 at 09:23
3

A single ton is a static function that allows you to keep track of your object instances, when you use a singleton you create an instance of the object but the instances always stays with the associated object.

Take this example:

$db1 = new Database();
$db2 = new Database();

as you can see that db1 and db2 are 2 new instances of Database therefore there not the same, now take this example.

$db1 = Database::Instance();
$db2 = Database::Instance();

And the code for Instance

class Database
{
    private static $_instance;

    public static Instance()
    {
        if(self::$_instance !== null)
        {
            //We have already stored the object locally so just return it.
            //This is how the object always stays the same
            return self::$_instance;
        }
        return self::$_instance = new Database(); //Set the instance.
    }
}

If you analyse the code you will so that no matter where you use Instance throughout your application your object will always be the same.

a static function is a method within a class/object isa type of method that can be used without the object being initialized.

In regards to __callStatic method, this is a Magic Method that's executed where a static method is not available.

For example:

class Database
{

    public static function first()
    {
        echo 'I actually exists and I am first';
    }

    public function __callStatic($name,$args)
    {
        echo 'I am '. $name .' and I was called with ' . count($args) . ' args';
    }
}

lets test them.

Database::first(); //Output: I actually exists and I am first

Database::second(); //Output: I am second and I was called with 0 args

Database::StackOverflow(true,false); //Output: I am StackOverflow and I was called with 2 args

Hope this helps you

RobertPitt
  • 56,863
  • 21
  • 114
  • 161
  • Thanks: Why does __callStatic use call_user_func_array? – Johnny Sep 15 '10 at 06:45
  • `call_user_func_array` is a function used to call a mathod or function, and example usage is like so `call_user_func_array('Database::Stack', array('Overflow'))` witch would call a static function within Database called Stack and pass in 1 argument, i mainly use this for MVC Patterns and Routers. – RobertPitt Sep 15 '10 at 07:41
0

Singleton means, that you have this class that will only have one object associated to it. So, this class will be only instantiated one single time, after that you will call a method with a name like getInstance() that will return your instance.

Static, means that to access that method or property you don't need and instance of that object, you can call that method directly with its class class::myMethod()

__callStatic is the way you access those static method. Is one of PHP magic-methods and is similar to __call with the difference I've just mentioned.

For the last question, That class only gets one connection to the database. If you add another method for example, executeSelect($sql) you will have something like:

public static function executeSelect($sql)
{
  if (self::$link)
  {
          self::getLink()
  } 
      // execute your query here...
  return null;
}

You will only need to call it like: Database::executeSelect($sql); and it will never get two connection to the DB simultaneously.

Garis M Suero
  • 7,974
  • 7
  • 45
  • 68
0

A singleton is an object that ensures that only one instance of itself is active at a time. That is, you can only make one per program, if you know what I mean.

A static method is one that can be called like a normal function, outside of object context. Like SomeClass:afunc() and not only $this->afunc().

Mark Snidovich
  • 1,055
  • 7
  • 11
0
<?php 
class DB {
protected static $instance;
protected function __construct() {
if(empty(self::$instance)) {
        try {
            self::$instance = new PDO("mysql:host=localhost;dbname=techprojects", 'root', '');
            self::$instance->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
        } catch(PDOException $error) {
            echo $error->getMessage();
        }
    }

}
public static function getInstance() {
    if(empty(self::$instance)) {
        try {
            new DB();
            //var_dump(self::$instance);
        } catch(PDOException $error) {
            echo $error->getMessage();
        }
    }
    //var_dump(self::$instance);
    return self::$instance;
}

private function __clone() {
    // Stopping Clonning of Object
}

private function __wakeup() {
    // Stopping unserialize of object
}
}
?>
<?php
try {
$db = DB::getInstance();
$db1 = DB::getInstance();
$sqlExample = 'SELECT * FROM keywords';
$stm = $db->prepare($sqlExample);
$stm->execute();
$result = $stm->fetchAll(PDO::FETCH_ASSOC);

var_dump($db);
var_dump($db1);
echo "<pre>";
print_r($result);
echo "</pre>";

} catch (Exception $e) {
print $e->getMessage();

}
 ?>