PDO Fatal error: Call to a member function prepare

2019-02-25 18:57发布

问题:

I'm having this error when I try to insert data in my database. I've searched the reasons of this error and I think my codes are right and I'm not supposed to get the error. My codes are these:

config.php

<?php
class DatabaseConnection{
    public function __construct(){
        try{
        $pdo = new PDO('mysql:host=localhost;dbname=test','root',''); //'mysql:host=host;dbname=dbname','mysqluser','mysqlpassword'
        }
        catch (PDOException $e){
            exit('Database error');
        }   
    }
}
?>

functions.php

<?php

require "config.php";

class LoginRegister{
    function __construct(){
        $database= new DatabaseConnection();
    }

    public function registerUser($username,$password,$name,$email){

        global $pdo; //THIS IS THE LINE WITH ERROR
        $query=$pdo->prepare("SELECT id FROM usuarios WHERE nombre_usuario=? AND correo_e=?");
        $query->execute(array($username,$email));
        $num=$query->rowCount();

        if($num==0){
            $query = $pdo->prepare("INSERT INTO usuarios(nombre_usuario,nombre_real,password,correo_e) VALUES (?,?,?,?)");
            $query->execute(array($username,$password,$name,$email));
            return true;
        }else{
            return print "Username or E_mail in use";
        }
    }
}
?>

register.php

<?php

require_once "functions.php";
$user = new LoginRegister();
?>

...HTML CODE...

<?php
if($_SERVER['REQUEST_METHOD'] == 'POST'){
    $username=$_POST['nombre_usuario'];
    $password=$_POST['password'];
    $name=$_POST['nombre_real'];
    $email=$_POST['correo_e'];

    if(empty($username) or empty($password) or empty($name) or empty($email)){
        echo "Error... Field must not be empty";
    }else{
        $register = $user->registerUser($username,$password,$name,$email);
        if($register){
            echo "Register done <a href='login.php'>Click here</a> for login";
        }else{
            echo "Username or E_mail in use";
        }
    }
}
?>

...HTML CODE...

As you can see, I declared the variable $pdo inside the registerUser functions, besides the variables that contain the name, username, password and email are parameters of the same function.

I know this is a several times duplicated question but I cannot solve this error with the solutions in the other ones.

回答1:

There are several problems with your code.

Two were explained in the other answer, which will make your code work (eventually it all was spoiled), but it's still wrong approach, which will connect to database as many times as many objects you have.

Change DatabaseConnection class this way

class DatabaseConnection{
    public $pdo;
    public function __construct(){
        $user = 'root';
        $pass = '';
        $dsn  = 'mysql:charset=utf8;dbname=test;host=localhost;charset=utf8';
        $opt  = array(
            PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        );
        $this->pdo = new PDO($dsn, 'root', '', $opt);
    }
}

Change LoginRegister constructor this way

function __construct($db){
    $this->db= $db;
}

And make register.php this way

require_once "functions.php";
$db = new DatabaseConnection();
$user = new LoginRegister($db->pdo);

and then in LoginRegister use $this->db instead of $pdo all the way.

The main idea to make $db connection an external service for the application class. Otherwise it will be all the same as despised global, but just in another form.



回答2:

I'm sorry but I must say hat horrible code. You are making all the worst mistakes. First NEVER use global, just never do it. Google it for an explanation why. Now the variables you create in your constructors only have scope there so they are never avaliable in your other class or method. That is why $pdo is not a PDO object it is just a local var with null value. Try this:

class DatabaseConnection{
    private $pdo;

    public function __construct(){
        try{
        $this->pdo = new PDO('mysql:host=localhost;dbname=test','root',''); //'mysql:host=host;dbname=dbname','mysqluser','mysqlpassword'
        }
        catch (PDOException $e){
            exit('Database error');
        }   
    }

    public function getPdo()
    {
        return $this->pdo;
}

class LoginRegister{
    private $database;

    function __construct(){
        $this->database= new DatabaseConnection();
    }

    public function registerUser($username,$password,$name,$email){

        $pdo = $this->database->getPdo();
        $query=$pdo->prepare("SELECT id FROM usuarios WHERE nombre_usuario=? AND correo_e=?");

Now this is still horrible but at least it will work. You really must read up on object oriented programming from a good book, one that also teaches you about design patterns and SOLID, DRY and other best practices.



回答3:

Here I have used php singleton PDO connection with mysql. Hope this will be help

<?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();

}
 ?>


回答4:

You don't set the $pdo to global on the database class (which is ok). You can create an internal database connection instead. See if this works:

config.php

<?php
class DatabaseConnection
    {
        // Create a singleton to store the connection for reuse
        private static $singleton;
        // save connection to singleton and return itself
        public function __construct()
           {
                // If your singleton is not set
                if(!isset(self::$singleton))
                    // assign it this class
                    self::$singleton = $this;
                // return this class
                return self::$singleton;
           }
        // This is a connection method because your __construct
        // is not able to return the $pdo connection
        public function connection()
            {
                try {
                        // as @Your Common Sense notes, there are some good
                        // PDO settings you can apply at connection time
                        $opts = array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,PDO::ATTR_EMULATE_PREPARES => false);
                        // Return your PDO Conneciton here.
                        return new PDO('mysql:host=localhost;dbname=test','root','',$opts);
                    }
                catch (PDOException $e){
                        exit('Database error');
                    }   
            }
    }

functions.php

<?php
require("config.php");

class LoginRegister
    {
        // This variable will store the db connection in this class
        private $con;
        // Construct will instantiate the DB
        function __construct()
            {
                // Instantiate connection class
                $pdo = new DatabaseConnection();
                // Assign internally the connection to $this->con
                $this->con = $pdo->connection();
            }

        public function registerUser($username,$password,$name,$email)
            {
                // Once assigned to $this->con, you can use the connection
                // throughout this class
                $query  =   $this->con->prepare("SELECT id FROM usuarios WHERE nombre_usuario=? AND correo_e=?");
                $query->execute(array($username,$email));
                // This should not use rowCount(),
                // instead use a COUNT(*). The manual states this is not
                // reliable on SELECT statements
                $num    =   $query->rowCount();

                if($num==0){
                    $query = $this->con->prepare("INSERT INTO usuarios(nombre_usuario,nombre_real,password,correo_e) VALUES (?,?,?,?)");
                    $query->execute(array($username,$password,$name,$email));
                    return true;
                }else{
                    return print "Username or E_mail in use";
                }
            }
    }
?>


标签: php mysql oop pdo