Empty clone magic method to prevent duplication.

this is code for a mysqli connection


<?php // RAY_temp_rgb192.php
error_reporting(E_ALL);

/**
* mysqli database: only one connection is allowed
*/
class Database
{
    private $_connection;
    //store the single instance
    private static $_instance;
    /**
    * get an instance of the database
    * @return Database
    */
    public static function getInstance(){
        if (!self::$_instance){
            self::$_instance= new self();
        }
        return self::$_instance;
    }
    /**
    * constructor
    */
    public function __construct(){
        $this->_connection = new mysqli('host','user','pass','db');
        //error handling
        if ($this->_connection->connect_error){
            trigger_error('Failed to connect to MySql: '.mysqli_connect_error(),E_USER_ERROR);
        }
    }


    /**
    * Empty clone magic method to prevent duplication.
    */
    private function __clone(){}
    /**
    * get the mysqli connection
    */
    public function getConnection(){
        return $this->_connection;
    }
}

// CREATE INSTANCE OF DATABASE AND GET CONNECTION OBJECT
$db = Database::getInstance();
$mysqli = $db->getConnection();

// RUN A QUERY
$sql = 'SELECT 1+1';
$res = $mysqli->query($sql);

// IF mysqli_query() RETURNS FALSE, LOG AND SHOW THE ERROR
if (!$res)
{
    $err
    = 'QUERY FAILURE:'
    . ' ERRNO: '
    . $mysqli->errno
    . ' ERROR: '
    . $mysqli->error
    . ' QUERY: '
    . $sql
    ;
    trigger_error($err, E_USER_ERROR);
}
// IF WE GET THIS FAR, THE QUERY SUCCEEDED AND WE HAVE A RESULT OBJECT IN $res
// AND SO WE CAN NOW USE $res IN OTHER MYSQLI FUNCTIONS


// DETERMINE HOW MANY ROWS OF RESULTS WE GOT
$num     = $res->num_rows;
$num_fmt = number_format($num);
if (!$num)
{
    echo "<br/>QUERY: $sql ";
    echo "<br/>FOUND NO DATA ";
    echo PHP_EOL;
}
else
{
    echo "<br/>QUERY: $sql ";
    echo "<br/>FOUND $num_fmt ROWS OF DATA ";
    echo PHP_EOL;
}
echo PHP_EOL;


// ITERATE OVER THE RESULTS SET AS AN OBJECT TO SHOW WHAT WE FOUND
echo PHP_EOL . 'USING MySQLi_Result::Fetch_<i>Object</i>(): ';
echo PHP_EOL;
while ($row = $res->fetch_object())
{
    // ROW BY ROW PROCESSING IS DONE HERE
    print_r($row);
    echo PHP_EOL;
}

Open in new window



 Empty clone magic method to prevent duplication.

prevent duplication of what

and cloning what
what is being cloned?

does the word 'clone' mean 'to copy' or 'to duplicate'

 Empty clone (duplication) magic method to prevent duplication.
LVL 1
rgb192Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Julian HansenCommented:
This is a singleton class - which means you only want one copy of it. If you were able to clone the object you would violate this requirement. By implementing an empty __clone method you ensure this does not happen

Read more here

http://php.net/manual/en/language.oop5.cloning.php

and cloning what
what is being cloned?
The object - in this case class Database

does the word 'clone' mean 'to copy' or 'to duplicate'
Essentially yes - with the __clone method though you can control exactly what gets copied to the new object (or not). By default the object properties are copied over to the new object.

Consider this example. The empty clone methods is commented out - run the code and look at the output - the result of the clone is a copy of the original object  - which you don't want. Uncomment the empty clone method and run again - you get an error. When implementing a singleton you don't want to be able to make a copy.
<?php
class myObject {
    private static $_instance;
    private $_someValue;
    
    public static function getInstance()
    {
        if (!self::$_instance){
            self::$_instance= new self();
        }
        return self::$_instance;
    }
    public function __construct(){
        $this->_someValue = 10;
    }
    public function update($value)
    {
        $this->_someValue = $value;
    }
    
//    private function __clone(){}
}

$obj = myObject::getInstance();

echo "<pre>";
echo 'Obj:' . PHP_EOL;
print_r($obj);
echo '</pre>';

$obj->update(111);
$newobj = myObject::getInstance();
$newobj->update(555);
echo "<pre>";
echo 'Obj: (both have same value because both pointing to the same instance)' . PHP_EOL;
print_r($obj);
echo 'NewObj' . PHP_EOL;
print_r($newobj);
echo '</pre>';

$anotherobject = clone $newobj;
$anotherobject->update(999);
echo "<pre>";
echo 'If cloning enabled then you have different objects different values' . PHP_EOL;
echo 'Obj:' . PHP_EOL;
print_r($obj);
echo 'NewObj' . PHP_EOL;
print_r($newobj);
echo 'AnotherObject' . PHP_EOL;
print_r($anotherobject);
echo '</pre>';
?>

Open in new window

0
Ray PaseurCommented:
Clone makes a copy of the object, including its properties at the time it was copied.  Contast new which makes an object from the class, with its properties in the original state.

By nullifying the __clone() method you prevent another programmer from creating a copy of your object.  If you want to prevent yourself from creating a copy of the object, just don't create a copy of the object.

The Singleton design pattern often gets a bad rap because it's a lot like "global" in that it creates a dependency (contrast a dependency injection).  Here's my teaching example of the singleton database connection.

<?php // RAY_database_singleton.php
error_reporting(E_ALL);


// SINGLETON DATA BASE CONNECTION CLASS
class Database
{
    // CLASS PROPERTIES ARE ALL PRIVATE
    private static $connection;
    private static $instance;

    // CONNECTION VALUES
    const DB_HOST = 'localhost';
    const DB_USER = '?';
    const DB_PASS = '?';
    const DB_NAME = '?';

    // NULLIFY THE CLONE
    final private function __clone() {}

    // OUR ONLY PUBLIC METHOD RETURNS THE CONNECTION
    public static function getConnection()
    {
        if (!self::$instance) self::$instance = new self();
        return self::$connection;
    }

    // CONSTRUCTOR RETURNS THE CONNECTION
    private function __construct()
    {
        self::$connection
        = new mysqli
        ( self::DB_HOST
        , self::DB_USER
        , self::DB_PASS
        , self::DB_NAME
        )
        ;
        if (self::$connection->connect_error)
        {
            trigger_error(self::$connection->connect_error, E_USER_ERROR);
        }
    }
}

$mysql1 = database::getConnection();
$mysql2 = database::getConnection();


// PROVE THAT THESE ARE THE SAME OBJECT http://php.net/manual/en/language.oop5.object-comparison.php
if ($mysql1 === $mysql2) echo 'EQUAL';

// SHOW THE OBJECT
var_dump($mysql1);

Open in new window

0
rgb192Author Commented:
Ray:

when I run this line
$mysql1 = database::getConnection();
which takes me to the class and then
if (!self::$instance) self::$instance = new self();
Why is the next step is the construct() method?

$mysql2 = database::getConnection();
the next step is to return
return self::$connection;


self::$_instance= new self();
why is the next step the construct method

Julian:

$newobj = myObject::getInstance();
does this say to set $newobj and $obj

>>
Clone makes a copy of the object, including its properties at the time it was copied.  Contast new which makes an object from the class, with its properties in the original state.

How does this relate to a database

Could multiple logins of the same database be instantiate without an empty clone



Both:

why is this useful for a database connection
Saying only one database connection?
0
10 Tips to Protect Your Business from Ransomware

Did you know that ransomware is the most widespread, destructive malware in the world today? It accounts for 39% of all security breaches, with ransomware gangsters projected to make $11.5B in profits from online extortion by 2019.

Julian HansenCommented:
$newobj = myObject::getInstance();
does this say to set $newobj and $obj
The effect of this is to point $newobj to a single instance of myObject - which is instantiated if it does not exist.

In other words the first call to getInstance creates an instance of myObject. All subsequent calls to getInstance result in the same instance being returned so in this case $newobj and $obj both refer to the same instance of myObj

Diagramatically

$newobj ---> myObject::_instance <---- $obj
0
Ray PaseurCommented:
if (!self::$instance) self::$instance = new self();
Why is the next step is the construct() method?
The single (as in "singleton") purpose of the class is to return a data base connection.  We want one and only one database connection.  So if there is not an instance of the data base connection, we run the constructor to create the data base connection.   Then we return the connection (which is a pointer).  If the singleton is called after an instance of the data base connection has been made, we return the connection that was made earlier (which is a pointer).  The order of methods (functions) inside a class definition is irrelevant.  The order in which they are called affects the functionality, but they can be defined in any order.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
rgb192Author Commented:
The single (as in "singleton") purpose of the class is to return a data base connection.

The effect of this is to point $newobj to a single instance of myObject - which is instantiated if it does not exist.


Thanks
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
PHP

From novice to tech pro — start learning today.