phprestparameters

For PHP REST API, how can I define/set the database connection parameters outside the class definition?


I'm using the PHP REST API example that appears all over the web. Here's basically what it is:

<?php
    
    require_once("Rest.inc.php");
    
    class API extends REST {

        const DB_SERVER     = "myhost";
        const DB_USER       = "myuser";
        const DB_PASSWORD   = "mypassword";
        const DB_NAME       = "mydb";
        
        public $data = "";
        private $db = NULL;
    
        public function __construct(){
            parent::__construct();
            $this->dbConnect();
        }

        private function dbConnect(){

            try {
                $this->db = new PDO("mysql:host=" . self::DB_SERVER . ";dbname=" . self::DB_NAME, self::DB_USER, self::DB_PASSWORD);
                $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            }
            catch(PDOException $e) {
                echo "Connection failed: " . $e->getMessage();
            }
        }
        
        
        public function processApi(){

            $func = strtolower(trim(str_replace("/","",$_REQUEST['rquest'])));

            if((int)method_exists($this,$func) > 0) {
                $this->$func();
            } else {
                $this->response('',404);
            }

        }

        private function activity(){
            ...
        }

        private function client(){
            ...
        }

        private function facility(){
            ...
        }

        etc...
        
        private function json($data){
            if(is_array($data)){
                return json_encode($data);
            }
        }
    }
    
    // Initiiate Library

    $api = new API;
    $api->processApi();

?>

It works fine, except that I don't want to hardcode the database connection parameters in that script. What is the best way (or is there a way) to separate them from this script? I can't use an include file inside the class declaration. Can I put the whole dbConnect() function in an include file, and include that outside the class definition? Any other options? I just want it so that there is nothing tying this script to a specific server. I would prefer to have the db server defined in a separate file that could be different on each server. I'm new to PHP and just wondering how the experts handle this.

**Edit: Got it working! This is a bit of a hybrid of the supplied answers.

dbConnect.php

<?php
    class DB {

        const DB_SERVER     = "myserver";
        const DB_USER       = "myuser";
        const DB_PASSWORD   = "mypassword";
        const DB_NAME       = "mydb";

        private $db = null;

        public function __construct() {
            try {
                $this->db = new PDO("mysql:host=" . self::DB_SERVER . ";dbname=" . self::DB_NAME, self::DB_USER, self::DB_PASSWORD);
                $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            }
            catch(PDOException $e) {
                echo "Connection failed: " . $e->getMessage();
            }
        }
    }
?>

api.php

<?php
    
    require_once("Rest.inc.php");
    require_once("dbConnect.php");
    
    class API extends REST {            
        public $data = "";
        private $db = null;
    
        public function __construct(DB $mydb){
            parent::__construct();
            $this->db = mydb->db;
        }
    }
    
    // Initiiate Library

    $api = new API(new DB());
    $api->processApi();

?>

Solution

  • You need to use Dependency Injection pattern, it will help you. And you will have something like this:

    interface DB
    {
        // Here you need to declare your common methods for all DB classes.
    }
    
    class MasterDB implements DB
    {
        const DB_SERVER     = "myhost";
        const DB_USER       = "myuser";
        const DB_PASSWORD   = "mypassword";
        const DB_NAME       = "mydb";
    
        private $db = null;
    
        private function __construct()
        {
            try {
                $this->db = new PDO("mysql:host=" . self::DB_SERVER . ";dbname=" . self::DB_NAME, self::DB_USER, self::DB_PASSWORD);
                $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            }
            catch(PDOException $e) {
                echo "Connection failed: " . $e->getMessage();
            }
        }
    }
    
    class SlaveDB implements DB
    {
        // Here you need to provide another connection
    }
    
    class API extends REST
    {
        private $db = null;
    
        public function __construct(DB $db)
        {
            parent::__construct();
            $this->db = $db;
        }
    }
    
    $api = new API(new MasterDB());
    // or
    $api = new API(new SlaveDB());
    $api->processApi();
    

    It is not a perfect example, but this one will help you solve your problem! Next step probably is - create parent or abstract class for MasterDB and SlaveDB...