Something wrong with Singleton class, no idea what

江枫思渺然 提交于 2020-01-24 17:04:07

问题


I have never done any Singleton class before and now I figured that for this DB connection it will be a good idea to make one, but I have no clue why it is not working. I really would appreciate if someone would help me out with this one since I want to learn how OOP works...

Anyway, I fixed it with just updating my PHP to latest version, now $DBH = new static(); works fine, thanks people.

I tried to use $DBH = new static(); isntead of $DBH = new self(); but then I have this error:

Parse error: syntax error, unexpected T_STATIC, expecting T_STRING or T_VARIABLE or '$' in mSingleton.php on line 14

Error:

Fatal error: Cannot instantiate abstract class Singleton in mSingleton.php on line 14

Files: (mSingleton.php)

abstract class Singleton
{

    protected $DBH;

    public static function getInstance()
    {
        if ($DBH == null)
        {
            $DBH = new self();
        }

        return $DBH;
    }

}

(mDBAccess.php)

<?php
//mDBAccess.php
//Removed values ofc
$db_host = "";
$db_name = "";
$db_user = "";
$db_pass = "";

include "mSingleton.php";

class DBAccess extends Singleton
{
    protected $DBH;

    function __construct()
    {
        try
        {
        $this->DBH = new PDO("mysql:host=$db_host;dbname=$db_name", $db_user, $db_pass);
        $this->DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
        }
        catch (PDOException $e)
        {
            echo $e->getMessage();
        }
    }

    public static function getDBH()
    {
        return self::getInstance()->DBH;
    }
}

(mLog.php)

<?php
//mLog.php
include "mDBAccess.php";

class Log
{

    public static function Add($action)
    {
        try
        {
            $DBH = DBAccess::getDBH();

            //Getting user IP
            $ip = $_SERVER['REMOTE_ADDR'];

            //Getting time
            $time = date('Y-m-d');

            //Preparing our SQL Query
            $values = array($ip, $action, $time);
            $STH = $DBH->prepare("INSERT INTO log (ip, action, time)
                                  VALUES (?, ?, ?)");

            //Excecuting SQL Query
            $STH->execute($values);
        }
        catch (PDOException $e)
        {
            echo $e->getMessage();
        }
    }

}
//testing..
Log::Add("ddd");

回答1:


You need to write

$DBH = new static();

See: Late Static Binding




回答2:


My workaround for PHP 5 < 5.3 for abstract Singleton classes.

Taken from: http://code.google.com/p/phpraise/source/browse/trunk/phpraise/core/RaiseSingleton.php

/**
 * RaiseSingleton abstract class
 * Defines a Singleton class
 *
 * @author Sam Yong
 * @license http://www.gnu.org/licenses/gpl.html GNU General Public License v3
 * @abstract
 * @package Raise.Core
 */
abstract class RaiseSingleton extends RaiseObject {

    /**
     * Prevent creation of a new instance
     * Constructor not set to final to allow overrides in subclass
     */
    protected function __construct() {}

    /**
     * Prevent cloning of the Singleton instance
     * @final
     */
    final private function __clone() {}

    /**
     * Return the Singleton instance
     * @return object
     * @staticvar static $__instance
     */
    public static function getInstance() {
        static $__instance;
        $class = get_called_class();
        return $__instance ? $__instance : $__instance = new $class();
    }
}

Basically, after tripping off all the phpRaise necessities:

abstract class Singleton {

    protected function __construct() {}

    final private function __clone() {}

    public static function getInstance() {
        static $__instance;
        $class = get_called_class();
        return $__instance ? $__instance : $__instance = new $class();
    }
}



回答3:


self points there to the abstract class, and you can't instantiate an abstract class, you have to use new static() if you want to keep that organization.




回答4:


$DBH = new self(); is the same as $DBH = new Singleton(); which has been marked as abstract to prevent instantiation.

You should be using Late Static Binding to initiate the new obhect of the child class, try using new static().




回答5:


I will say upfront I am not proficient with PHP but there are a few things that stand out to me.

  • $DBH is redefined in DBAccess where it is first declared in Singleton.
  • $DBH in Singleton is not declared static, so how could $DBH = new static() work? Unless late binding with static converts $DBH into a static storage area.
  • If you convert $DBH in Singleton into a static variable, you'll have issues if anything else every derives from Singleton.

Unless someone wiser comes along and can make a Singleton class that can be utilized for any subclass of it your best bet is to put the logic directly into your DBAccess class. If someone can fix the semantic and syntax errors I'd appreciate it.

class DBAccess
{
    private static $_instance;

    protected $DBH;

    function __construct()
    {
        try
        {
            $this->DBH = new PDO("mysql:host=$db_host;dbname=$db_name", $db_user, $db_pass);
            $this->DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
        }
        catch (PDOException $e)
        {
            echo $e->getMessage();
        }
    }

    public static function getDBH()
    {
        if ($_instance == null)
            $_instance = new DBAccess();
        return $_instance->DBH;
    }
}


来源:https://stackoverflow.com/questions/4914302/something-wrong-with-singleton-class-no-idea-what

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!