Jump to content

Difference between an instance variable inside the class and one outside the class..?


BillInKCMO
Go to solution Solved by requinix,

Recommended Posts

Weary of getting frowned at over on StackOverflow, so...HI THERE.

Consider these two blocks of code. Is there any functional difference between them?

class myClass {
    
    private static $instance;
    
    public static function instance(){
        if ( ! isset( self::$instance ) ) {
            self::$instance = new self;
        }
        return self::$instance;
    }
    
    public function __construct() {
        
    }
    
}
$my_class_name = MY_CLASS_NAME::instance();

and 

class myClass {    
    public function __construct() {
        // blah blah blah
    }
}
$my_class_name = new MY_CLASS_NAME();

 

Link to comment
Share on other sites

  • Solution
2 hours ago, BillInKCMO said:

Weary of getting frowned at over on StackOverflow, so...HI THERE.

Forums are way better than StackOverflow for anything but the most trivial and straight-forward of questions. Forget trying to discuss anything on SO...

 

2 hours ago, BillInKCMO said:

Consider these two blocks of code. Is there any functional difference between them?

Yes: the first one allows one and only one instance of the class, while the second allows anyone to create as many as they want.

Which also means the first one's constructor should be private. Public could be okay but that means two paradigms for the class and that's one too many.

Link to comment
Share on other sites

Quote

Forums are way better than StackOverflow for anything but the most trivial and straight-forward of questions.

So I have learned over the years. When I got the notification that I was close to being banned for asking so many questions I gave up.\

I'm largely self-taught and while I could - without thinking about it too much - write you a really efficient CRM or shopping cart, there are some of the finer points that I'm still learning.

Thanks for the answer!

Edited by BillInKCMO
typos
Link to comment
Share on other sites

If you follow requinix's advice and make the constructor private in the first code sample it's a textbook example of the Singleton pattern. While there was a period a few years ago that people railed against using Singletons, the furor seems to have died down recently. In my experience, 90 percent of the time it's perfect for things like setting up database connections.

  • Great Answer 1
Link to comment
Share on other sites

Heck I even learn something new reading these threads.

Here's my Database Connection:

<?php


namespace PhotoTech;

use mysql_xdevapi\Exception;
use PDO;
use PDOException;

class Database {

    private PDO $_connection;
    // Store the single instance.
    private static ?Database $_instance = null; // Don't initialize before it is called:

    // Get an instance of the Database.
    // @return Database:
    protected static function getInstance(): Database
    {
        if (!self::$_instance) {
            self::$_instance = new self();
        }
        return self::$_instance;
    }

    public static function pdo(): PDO
    {
        $db = static::getInstance();
        return $db->getConnection();
    }

    // Constructor - Build the PDO Connection:
    private function __construct() {
        try {
        $db_options = [
            /* important! use actual prepared statements (default: emulate prepared statements) */
            PDO::ATTR_EMULATE_PREPARES => false
            /* throw exceptions on errors (default: stay silent) */
        , PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
            /* fetch associative arrays (default: mixed arrays)    */
        , PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
        ];
        $this->_connection = new PDO('mysql:host=' . DATABASE_HOST . ';dbname=' . DATABASE_NAME . ';charset=utf8', DATABASE_USERNAME, DATABASE_PASSWORD, $db_options);
        } catch (PDOException $e) {
            //echo $e;
            //echo "<pre>" . print_r($e->errorInfo, 1) . "</pre>";
            if ($e->errorInfo[1] === 1045) {
                echo "Can't Connect to Database " . $e->errorInfo[1] . "<br>";
                return false;
            }

            throw $e; // If PDO Exception error can't handle it throw it to Exception:

        } catch (Exception $e) {
            echo 'Caught exception: ', $e->getMessage(), "\n"; // Not for a production server:
        }
        return true;
    }

    // Empty clone magic method to prevent duplication: *Probably Not Even Needed Now*
    private function __clone() {

    }

    // Get the PDO connection:
    protected function getConnection(): PDO
    {
        return $this->_connection;
    }

}

I think (not totally sure) that before the constructor had to be public and that is why the Empty Clone Magic had to be used?

 

Just something extra to use this class all one has to do is

$stmt = Database::pdo()->prepare($sql); // Prepare the query:

 

Link to comment
Share on other sites

On 11/11/2022 at 11:56 PM, BillInKCMO said:

Is there any functional difference between them?

The former is an implementation of the Singleton Pattern
Every time you call the instance() function, you get the same instance of the object returned.  

The latter simply creates a new instance of the class each and every time. 

Regards, 
   Phill  W.

 

Link to comment
Share on other sites

On 11/11/2022 at 9:33 PM, BillInKCMO said:

So I have learned over the years. When I got the notification that I was close to being banned for asking so many questions I gave up.\

I'm largely self-taught and while I could - without thinking about it too much - write you a really efficient CRM or shopping cart, there are some of the finer points that I'm still learning.

Thanks for the answer!

I have a bit over 14k rep at SO with 99.9% of that from answering questions.  I've all but given up on going there, as they have made the site, despite protestations to the opposite, miserable for new or inexperienced developers and for anyone trying to help them, especially in the #php tag.  There are a few overzealous mods who have made it their mission to criticise or close questions from novices, even going so far as to attack people answering these questions.  It's gotten to the point that there is really no point in answering anymore questions, because the questions get closed or pointed to existing answers even when there is a substantive details that make the pre-existing question irrelevant.   SO's been going in this direction for quite a while, but to read that someone would be threatened with expulsion from SO for asking too many questions, is mind boggling.   

Link to comment
Share on other sites

On 11/12/2022 at 8:02 AM, Strider64 said:

Heck I even learn something new reading these threads.

Here's my Database Connection:

I think (not totally sure) that before the constructor had to be public and that is why the Empty Clone Magic had to be used?

 

Just something extra to use this class all one has to do is

$stmt = Database::pdo()->prepare($sql); // Prepare the query:

 

Yes recently (v7) PHP was changed so that you can have a private constructor in a class meant to be used statically, so that it is impossible to instantiate an object of that class externally using the 'new' keyword.  

This is not related to object cloning.

Object cloning requires the 'clone' keyword.  

 

<?php

$obj1 = new stdClass();

$obj1->foo = 'Object1';

$obj2 = $obj1;

// $obj1 and $obj2 point to same object.  They "reference" the same object

echo $obj1->foo . PHP_EOL;

// Changing $obj2 changes the underlying object pointed to by both variables
$obj2->foo = 'Object2';

// Changed the property of $obj2, and thus This prints 'Object2'
echo $obj1->foo . PHP_EOL;

// This time we use clone
// Object 3 is an independent object, only the properties were copied
$obj3 = clone $obj1;

// Changing $obj3 does not change $obj1/$obj2
$obj3->foo = 'Object3';

echo $obj1->foo . PHP_EOL;
// Still prints 'Object2'

echo $obj3->foo . PHP_EOL;
// Prints object3

 

Looking at a private constructor example, does this affect the use of new?   Yes.  You can't instantiate it with new, only using a static method.

<?php

class Test {
    private ?string $name;
    private ?string $guid;
    
    private function __construct(?string $name = null) {
        $this->name = $name;
        $this->guid = uniqid('', true);
    }
    
    public static function makeTest(?string $name = null) {
        return new static($name);    
    }
    
    public function getName() {
        return $this->name;
    }
    
    public function getGuid() {
        return $this->guid;
    }
}

$foo = new Test();

This triggers a runtime error:  Fatal error: Uncaught Error: Call to private Test::__construct()

However, using makeTest() to create an object, does this somehow prevent variable assignment or clone behavior?  Not at all!

class Test {
    private ?string $name;
    private ?string $guid;
    
    private function __construct(?string $name = null) {
        $this->name = $name;
        $this->guid = uniqid('', true);
    }
    
    public static function makeTest(?string $name = null) {
        return new static($name);    
    }
    
    public function getName() {
        return $this->name;
    }
    
    public function getGuid() {
        return $this->guid;
    }
}


$obj1 = Test::makeTest();
echo "Name:" . $obj1->getName() . PHP_EOL;
echo "Guid:" . $obj1->getGuid() . PHP_EOL;

$obj2 = Test::makeTest('Object2');
echo "Name:" . $obj2->getName() . PHP_EOL;
echo "Guid:" . $obj2->getGuid() . PHP_EOL;

$obj3 = $obj2;
echo "Name:" . $obj3->getName() . PHP_EOL;
echo "Guid:" . $obj3->getGuid() . PHP_EOL;

$obj4 = clone $obj2;
echo "Name:" . $obj4->getName() . PHP_EOL;
echo "Guid:" . $obj4->getGuid() . PHP_EOL;

 

You will see something similar to this:

Name:
Guid:6372930b031f27.11028500
Name:Object2
Guid:6372930b032385.75458089
Name:Object2
Guid:6372930b032385.75458089
Name:Object2
Guid:6372930b032385.75458089

 

 

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.