Error when instantiating two or more PDO in different classes

Asked

Viewed 207 times

0

I will start with the error displayed:

Fatal error: Uncaught Pdoexception: You cannot serialize or unserialize PDO instances in [no active file] on line 0

In the project I have the class Carts and the class Markings, both are subclasses of a class called Database, where I connect to the database and run CRUD, etc.

The error happened when I tried to call two controller at once, one to list the class records Carrinhos and another to list the class records Marcas. Follows the methods used:

To connect to the bank: (is executed when the class Carts and the class Markings are instantiated)

private function connect($line)
{
    if(is_null($this->connection))
    {
        try {
            if ($conn = $this->tryConnect($line, $this->database))
                return $conn;
            else
                return $this->tryConnect($line);
        } catch (Exception $e) {
            Log::register($e->getMessage() . "In l:" . __LINE__);
            return false;
        }
    }
    else
        return $this->connection;

}
private function tryConnect($line, $dbname = null)
{
    try
    {
        if(!is_null($dbname))
            $dbname =  ';dbname=' . $dbname;
        Session::set("teste", $dbname);
        $conn = new PDO
        (
            'mysql:host=' . Settings::get('dbhost') . $dbname,
            Settings::get('dbuser'),
            Settings::get('dbpassword'),
            array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8")
        );
        $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        $conn->setAttribute(PDO::ATTR_ORACLE_NULLS, PDO::NULL_EMPTY_STRING);
        Log::register("Is connect \nIn l:".$line, "mysql_success");
        return $conn;
    }
    catch (Exception $e)
    {
        Log::register($e->getMessage()."In l:" .__LINE__);
        return false;
    }
}

To list the records of each use class:

public function listAll($pager = null, $criteria = null)
{
    $data = $this->clear();
    $sql = "";

    if($pager instanceof Pager and $criteria instanceof Criteria)
        $sql =  "SELECT *" . " FROM {$this->addCriteria($criteria)} LIMIT {$pager->range()['min']}, {$pager->range()['max']};";
    else if($pager instanceof Pager)
        $sql =  "SELECT *" . " FROM {$data['table']} LIMIT {$pager->range()['min']}, {$pager->range()['max']};";

    else if($criteria instanceof Criteria)
        $sql = "SELECT {$criteria->getSelect()}" . " FROM {$this->addCriteria($criteria)};";
    else if(!$pager instanceof Pager)
        $sql = "SELECT *" . " FROM {$data['table']};";

    if($this->debug)
        var_dump($sql);

    if($this->connection = $this->connect(__LINE__))
    {
        try
        {
            $prepare = $this->connection->prepare($sql);
            if($criteria instanceof Criteria)
                foreach ($criteria->getValues() as $key => $value)
                    $prepare->bindValue(":$key", $value);

            $prepare->execute();
            $list = $prepare->fetchAll(PDO::FETCH_ASSOC);
            $return = array();

            foreach ($list as $row)
                array_push($return, $this->fills($row));

            Log::register("List All execute of: " . $sql. "\nIn l:" . __LINE__, "mysql_success");
            return $return;
        }
        catch (Exception $e)
        {
            Log::register($e->getMessage()."In l:" .__LINE__);
        }
    }
    return false;
}

Where Pager and Criteria do not see the case.

And finally the method to end the connection:

private function close($prepare, $action, $line)
{
    if($prepare instanceof PDOStatement)
    {
        if($prepare->execute())
        {
            Log::register($action . " execute of: " . $prepare->queryString . "\nIn l:$line", "mysql_success");
            foreach ($_POST as $key => $value)
                unset($_POST[$key]);
            $this->connection = null;
            Saved::destroy();
            return true;
        }
    }
    return false;
}

From what I see the error would be that it is trying to use two simultaneous connections in the same database, the solution I searched seems to be to use the __Sleep() or __wakeup(), but searching I could not understand very well, someone could help me in solving the error?

  • Error says a Pdoexception was released but had none try to capture it. The code that generates the error may not be in the question. A suggestion to try to isolate the error is first check if it happens with PDO or multiple instances. If possible install a debuger as Xdebug and configure an IDE (eclipse/phpStorm) and run its code with break point then just go step by step until the error breaks.

2 answers

0

From what I understand of your code you’re trying to make a connection class using the default Singleton. I think the way is this. A connection class in the Singleton pattern would look like this:

<?php
class SingletonDB
{
    public $db;
    private static $instance;

    private function __construct()
    {
        $this -> dbhc= new PDO('mysql:host=localhost;dbname=example', "root", "");
    }

    //singleton pattern
    public static function getInstance()
    {
        if (!isset(self::$instance))
        {
            $object = __CLASS__;
            self::$instance = new $object;
        }
        return self::$instance;
    }
}

?>

Taking an instance of the class

$db = database::getInstance();

Source: https://acomputerengineer.wordpress.com/2013/06/16/pdo-connection-class-in-php-oop-approach-with-singleton-pattern/

0


The error was not in the instantiation of PDO as I found (because in the searches all results spoke this same problem), and yes because it was storing a array of objects in a session variable, even doing serialize was not working.

The solution was to pass the objects to array, so I took advantage of a method I had in my Database that turns my model in array:

private function clear()
{
    $attr = get_class_vars(get_class($this->object));
    $attr2 = get_class_vars('Database');

    foreach ($attr as $key => $value)
        if($key != 'table' and key_exists($key, $attr2))
            unset($attr[$key]);

    $data = array();
    foreach ($attr as $key => $value)
        $data[$key] = $this->object->$key;
    return $data;
}

So I made a public method to get the object already as an array:

public function vars()
{
    return $this->clear();
}

In the controller, I created a method that takes the list of objects and turns it into a list of arrays:

public function toArray($object)
{
    if(is_array($object))
    {

        $variables = array();
        foreach ($object as $o)
        {
            array_push($variables, $this->scan($o));
        }
        return $variables;
    }
    else if(is_object($object))
    {
        return $this->scan($object);
    }
}

private function scan($o)
{
    if(is_object($o))
    {
        $vars = $o->vars();
        foreach ($vars as $k => $v)
        {
            if(is_object($v))
            {
                $vars[$k] = $this->toArray($v);
            }
        }
        return $vars;
    }
}

For others the code may seem strange, but it adapts the framework structure: https://github.com/LeonardoVilarinho/framework

Browser other questions tagged

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