Call to a Member Function prepare() on null in

Asked

Viewed 485 times

1

I got this class that connects to Mysql through PDO, in this link. It works just fine. But I decided to turn it into a static class. And here’s the modified code.

class db {
    private static $dsn;
    private static $username;
    private static $password;
    private static $db; 
    private static $conn;

    private static $arrConnAttr;//Array of connection attributes. Ex: ["PDO::ATTR_ERRMODE", "PDO::ERRMODE_EXCEPTION"]
    private static $pathErroLog;//Path to save the erro log files. Ex:$_SERVER['DOCUMENT_ROOT'] . "/myDirRootProject/LogError"
    private static $arrCatchConnResult;//Path to save the erro log files. Ex:$_SERVER['DOCUMENT_ROOT'] . "/myDirRootProject/LogError"
    private static $die;//If we set $setValues["die"]=NULL, during the object initialization, errors will not stop the process. 

    public static $sql;

    public function __construct(array $setValues=NULL) {          

         xdebug_break();
         $arrInitDefault["dsn"]="localhost";
         $arrInitDefault["username"]= "root";
         $arrInitDefault["password"]="";
         $arrInitDefault["db"]="drset2014";



         $arrInitDefault["arrConnAttr"]= ["PDO::ATTR_ERRMODE"," PDO::ERRMODE_EXCEPTION"];

         $arrInitDefault["pathErroLog"]= dirname(__FILE__)."/Log/Error";//Default path to dir. Note: error pathLog can be "/Log/Error/UserName" or "/Log/Error/UserId", etc
         $arrInitDefault["die"]=  TRUE;         

         $arrInitDefault["sql"]=  FALSE;


         if(!is_null($setValues)){
              $arrInitDefault=  array_merge($arrInitDefault,$setValues);
          }

          //After merge, initialaze private variables with result merged $arrValues

          self::$dsn = $arrInitDefault["dsn"];
          self::$username= $arrInitDefault["username"];
          self::$password= $arrInitDefault["password"];
          self::$db= $arrInitDefault["db"];

          self::$arrConnAttr= implode(",", $arrInitDefault["arrConnAttr"]);
          self::$pathErroLog=$arrInitDefault["pathErroLog"];
          self::$die=$arrInitDefault["die"];
         //This try and catch  is only to estabilish the connection during the initialization
         try {

                $dns=self::$dsn;
                $username=self::$username;
                $password=self::$password;
                $db=self::$username;

                self::$conn= new PDO("mysql:host=$dns; dbname=$db", "$username", "$password");//Now private $conn is a PDO object
                self::$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);        

         }// End of try
         catch(PDOException $e){//If had some error. The PDO object ($this->conn) could not be created. Throw an error.      
          self::$arrCatchConnResult = self::saveLogError($e->getMessage());//Save a message in the log file and throw a message
          $msg=self::$arrCatchConnResult["strToHTML"];
          self::$conn=null;                 
                 if(self::$die){                   
                       die($msg);
                 }
           }
    }

    public static function saveLogError($msg=NULL,$sql=NULL) {
     #xdebug_break();

     xdebug_break();
       $year = date("Y");
       $month = date("M"); 
       $day = date("d");
       $dt = date("d.M.Y_H.i.s");

       $pathErroLog=  self::$pathErroLog."/".$year."/".$month."/".$day."/";
       if (!is_dir($pathErroLog)) {
          mkdir($pathErroLog,0777,true);
       }//If is not a dir, create it.

       $sqlErrorStringTXT="";
       $sqlErrorString="";
       if(!is_null($sql)){
        $sqlErrorStringTXT = "Sql: $sql";
        $sqlErrorStringHTML = "<kbd>Sql</kbd>: $sql";
       }

///////////////  Maybe should be good save errors in database too.   

$strToTxt=<<<EOF
>>>>>  Mensagem de erro:  <<<<< \n 
Date:     $dt \n
Msg:     $msg \n  
$sqlErrorStringTXT \n
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
EOF;

//Save error message to the file
$f=$pathErroLog."$dt.txt";
$myfile = fopen($f, "w") or die("Unable to open file!");
fwrite($myfile, $strToTxt);
fclose($myfile);

//Create a string to be displayed in the broser
$strToHTML=<<<EOF
<div class="alert alert-danger" role="alert">
Date:     $dt <br/>
Msg:     <span class="label label-danger">$msg</span><br/>  
$sqlErrorStringHTML<br/>
</div>
EOF;

$arrCatchConnResult["status"]=0;
$arrCatchConnResult["strToTxt"]=$strToTxt;
$arrCatchConnResult["strToHTML"]=$strToHTML;

return $arrCatchConnResult;

}//End of saveLogError()

    public static function get_values() {
              try {           
                     $stmt = self::$conn->prepare(self::$sql); 
                     $stmt->execute();
                     while ($field = $stmt->fetch(PDO::FETCH_ASSOC)) {
                      $arrResult[]=$field;
                    }
                    return $arrResult; 
              } 
              catch (PDOException $e) {
                    self::$arrCatchConnResult =  self::saveLogError($e->getMessage(),  self::$sql);//Save a message in the log file and set a message   
                    $msg= self::$arrCatchConnResult["strToHTML"];
                    self::$conn = null;
                    if(self::$die){                           
                          die($msg);
                    }
              }
         }


}//End of class db

On my index.php page, I’m calling it that way:

include './class/db.php';
db::$sql ="select * from city";         
echo "<pre>";
   print_r(db::get_values());
echo "</pre>";

When I turn the page I have a mistake like:

Fatal error: Call to a member function prepare() on null in C:\xampp\htdocs\drReference\private\class\db.php on line 126

It seems that when transforming into Static class the constructor is not called, since not in these types of classes the creation of objects is not necessary. I could try to solve this by passing the constructor code to a connect function for example, and calling this function every time a query is started.

My question is, is there any way to continue with Static class and force the boot by going through the constructor?

  • You can move the constructor code to a method called connect() for example and call it inside get_values(). Is a suggestion there are other ways to resolve this situation.

  • I was wondering if there’s another possibility going through the builder

  • If everything in the class is Static it makes no sense to put any code in the constructor. What is static is shared with(only) the class, what is not Static is only valid for that object.

  • It makes sense. So it’s better to create another static boot method.

No answers

Browser other questions tagged

You are not signed in. Login or sign up in order to post.