karma Posted January 22, 2015 Share Posted January 22, 2015 Hi All, I've been interested in writing a PHP pdo configuration file so that I can include connections in various files on my site. While I was looking up some possible solutions I stumbled across an interesting post on stack overflow http://stackoverflow.com/questions/11369360/how-to-properly-set-up-a-pdo-connection The first responder suggested the code below. However, I don't understand how to access the connection and make query calls. I'm confused by how it's possible to return a variable name as an object { return new $name( $this->connection ) }. Also, If someone could explain what the author means by { $something = $factory->create('Something');}. Wouldn't the "Something" need to be a class? And how would that class get the db connection? All the best, Karma $provider = function() { $instance = new PDO('mysql:......;charset=utf8', 'username', 'password'); $instance->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $instance->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); return $instance; }; class StructureFactory { protected $provider = null; protected $connection = null; public function __construct( callable $provider ) { $this->provider = $provider; } public function create( $name) { if ( $this->connection === null ) { $this->connection = call_user_func( $this->provider ); } return new $name( $this->connection ); } } $factory = new StructureFactory( $provider ); $something = $factory->create('Something'); $foobar = $factory->create('Foobar'); Quote Link to comment Share on other sites More sharing options...
requinix Posted January 22, 2015 Share Posted January 22, 2015 What that solution provides is more along the lines of dependency injection than a straight-up factory (though there is often overlap between the two). The anonymous function provides a way of injecting the PDO dependency into assorted classes, but it's still up to you to provide those "assorted classes". In that example code, what you pass to StructureFactory::create() is a name of a class. That class needs to have a constructor that takes a pre-configured PDO object as its only argument. It doesn't have to worry about establishing the connection on its own. class Something { // $factory->create('Something') private $pdo = null; public function __construct(PDO $pdo) { $this->pdo = $pdo; } // methods to do queries and whatever }There would also be a Foobar class along the same lines. The class is responsible for issuing queries through PDO and reading resultsets, that hasn't changed, but now it doesn't need to know connection information. I'm confused by how it's possible to return a variable name as an object { return new $name( $this->connection ) }.That's a feature of PHP called "variable variables". Basically, in some places you can use a variable's value instead of writing something directly into code.In this case, $name is the name of a class and PHP will instantiate it as if you had written return new Something or return new Foobar. Quote Link to comment Share on other sites More sharing options...
karma Posted January 22, 2015 Author Share Posted January 22, 2015 (edited) Hi Requinix, Thank you for your thorough response-- it was very helpful. In the factory class, Something, is it necessary to typecast $pdo? Would you suggest this approach to creating DB connections, or is there something more effective? In the Something class I wanted to be able to make insert & select queries. Below is the code I was planning on using, but I wasn't sure if this was the right approach. Do you see any improvements that can be made? Thank you so much for your help! I really appreciate it. class Something { private $pdo = null; public function __construct(PDO $pdo) { $this->pdo = $pdo; } public function push($sql) { try { $stmt = $this->pdo->query($sql); return $stmt->fetchAll(PDO::FETCH_ASSOC); } catch (PDOException $ex) { throw new Exception($ex->getMessage()); } } public function fetch($sql, $params = array()) { try { $stmt = $this->pdo->prepare($sql); $stmt->execute($params); return $stmt->fetchAll(PDO::FETCH_ASSOC); } catch (PDOException $ex) { throw new Exception($ex->getMessage()); } } } Edited January 22, 2015 by karma Quote Link to comment Share on other sites More sharing options...
Solution requinix Posted January 22, 2015 Solution Share Posted January 22, 2015 (edited) Thank you for your thorough response-- it was very helpful. In the factory class, Something, is it necessary to typecast $pdo?Actually that's a "type hint": you're hinting to PHP and other developers what type of argument is supposed to be passed.A type cast is $int = (int)$string;No, it's not necessary, but it's a Good Idea. Would you suggest this approach to creating DB connections, or is there something more effective?The anonymous function style it has been becoming more popular over the last year or so, with a couple frameworks designed in a similar style, but like that it's a bit too limiting for my taste.And frankly I don't see what benefit the function and StructureFactory, at least as they currently are, offer over just making a new PDO object: you're still writing the connection information and the name of the PDO wrapper class (ie, the class you use to interact with PDO) directly in your code. I prefer the global configuration/settings style. For example, a JSON file containing { "databases": { "connection1": { "dsn": "mysql:...;charset=utf8", "username": "username", "password": "password", "class": "Something" }, "connection2": { "dsn": "mysql:...;charset=utf8", "username": "username", "password": "password", "class": "Foobar" } } }and abstract class Db { protected $pdo = null; protected function __construct(PDO $pdo) { $this->pdo = $pdo; } public static function get($name = "default") { // somehow get the information from the configuration file // probably a class somewhere to help with this $info = Configuration::get("databases", $name); if (!$info) { throw new Exception("No database configuration for {$name}"); } $pdo = new PDO($info["dsn"], $info["username"], $info["password"]); $class = $info["class"]; return new $class($pdo); } }(as a rough version - I'd do more, like use interfaces, add some inheritable helper methods...) // the "connectionN" name, which is a horrible name to use, is a fixed value and completely separate from the information $something = Db::get("connection1"); $foobar = Db::get("connection2");The benefit is that while you still have to put the connection information somewhere (obviously), you aren't putting the information in code but rather somewhere that can be easily edited. Edited January 22, 2015 by requinix Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.