简体   繁体   中英

OOP PHP load not returning correct object

Problem: When I load model with load object, it will NOT return second model.

Take a look at class Test where I load model with load object. Code $this->two will return object One ( should load object Two ).

Q: How to solve this problem? I am open your suggestions/ideas/code

Current Result:

one is working
object(One)#3 (1) { ["error":"Model":private]=> NULL }
one is working
object(One)#4 (1) { ["error":"Model":private]=> NULL }

Correct result:

one is working
object(One)#3 (1) { ["error":"Model":private]=> NULL }
two is working
object(Two)#4 (1) { ["error":"Model":private]=> NULL }

PHP:

one_model.php

<?php

class One extends Model {

    public function test() {
        echo '<p>one is working</p>';
    }

}

two_model.php

<?php

class Two extends Model {

    public function test() {
        echo '<p>two is working</p>';
    }

}

index.php

<?php

class Controller {

    public $load;

    public function __construct() {
        $this->load = new Load();
    }

}

class Load {

    public function model($name) {
        if (!class_exists($name)) {
            require(strtolower($name) . '_model.php');
        }
        $model = new $name;
        return $model;
    }

}

class Model extends PDO {

    private $error;

    public function __construct() {

        $options = array(
            PDO::ATTR_PERSISTENT => true,
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
        );

        try {
            $dsn = "mysql:dbname=test;host=localhost;charset=utf8";
            parent::__construct($dsn, 'root', '', $options);
        }
        catch (PDOException $e) {
            $this->error = $e->getMessage();
        }
    }

}

class Test extends Controller {

    public $one;
    public $two;

    public function __construct() {
        parent::__construct();

        $this->one = $this->load->model('one');
        $this->two = $this->load->model('two');
    }

    public function testing() {
        $this->one->test();
        var_dump($this->one);
        $this->two->test();
        var_dump($this->two);
    }

}

// Usage
$test = new Test();
$test->testing();

I moved PDO wrapper from Model to separate class and create object for database connection.

Is this good approach ? Is this " waste of resources "?

class Database extends PDO {

    private $error;

    public function __construct() {

        $options = array(
            PDO::ATTR_PERSISTENT => true,
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
        );

        try {
            $dsn = "mysql:dbname=test;host=localhost;charset=utf8";
            parent::__construct($dsn, 'root', '', $options);
        }
        catch (PDOException $e) {
            $this->error = $e->getMessage();
        }
    }

}


class Model {

    public $db;

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

}

The problem there seems to be that you are passing PDO::ATTR_PERSISTENT => true to the PDO constructor. This will tell PDO to cache and reuse connections - as you no doubt intended - but it also appears to cause PDO to produce clones of the first PDO instance generated within the scope of a single script, including the child class used to create that first instance. (Doesn't seem to be a lot of documentation on this though.)

If you require persistent connections, my recommendation would be to define the models in a way that doesn't require them to be extended from PDO. That really shouldn't be a necessary in any case.

For example, if your code uses a CRUD model, abstracting that away from the model, and putting the database code into the base of that instead of the actual Model, might solve this nicely. For instance, given these as a base:

class DatabaseSingleton {
    private static $instance;

    public static function get() {
        if (!self::$instance) {
            $options = array(
                PDO::ATTR_PERSISTENT => true,
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
            );
            $dsn = "mysql:dbname=test;host=localhost;charset=utf8";
            self::$instance = new PDO($dsn, 'root', '', $options);
        }
        return self::$instance;
    }
}

abstract class Crud {
    private $pdo;

    public function __construct() {
        $this->pdo = DatabaseSingleton::get();
    }

    public function create(...) {
        $this->pdo->...
    }
    public function retrieve(...) {
        $this->pdo->...
    }
    public function update(...) {
        $this->pdo->...
    }
    public function delete(...) {
        $this->pdo->...
    }
}

Then your models could simply be defined as children of:

abstract class Model extends Crud {

    public function __construct() {
        parent::__construct();
        // Etc...
    }
}

And the CRUD functionality defined in Crud would be available to to them, using the single PDO instance provided by the singleton.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM