I'm planning to use a PHP PDO wrapper class from here: http://www.imavex.com/php-pdo-wrapper-class/
I initialized the class with:
$db = new db("mysql:host=$sitedbHost;port=3306;dbname=$sitedbName", "$sitedbUser", "$sitedbPass");
The problem is, that I don't like the idea to make global $db on every function on my other classes like this:
class User
{
function getUserDomains($user_id)
{
global $db;
return $db->select("domains");
}
}
Any help will be highly appreciated.
If you class requires it in order to work, you can inject it in the constructor:
class User {
public function __construct(Database $db) {
$this->db = $db;
}
}
You can then access the database object from $this->db. (Note, I assumed $db is an instance of the Database class. Change it as appropriate).
Here is something for you:
Check new PDO Class Wrapper on GitHub
I don't like the idea to make global $db on every function on my other classes
Well, make it global in constructor only (or pass it as a parameter), and then use as a class variable,
return $this->db->select("domains");
Honestly, you can't avoid passing $db to the function somehow. There is no magic. Whatever fashionable way you choose, you'll end up with setting your $db variable this way or another, no matter how it's called, "dependence injection", "global" or "use the Force, Luke".
I'd vote for global as it's plain and simple.
By the way, this framework is inflexible and insecure. Better use safeMysql as it's way more secure and flexible
Related
I had this error:
Notice: Undefined variable: mysqli in /path/to/component.php on line 24
This was inside this section of code:
class Component {
public function foo() {
// something using $mysqli;
}
}
To fix it, I have to add global $mysqli into my foo method - I understand that, but this isn't very practical for me, as I'd prefer to simply make $mysqli accessible within all classes by default.
Is this possible?
The short answer is: no. There isn't a way to change the way scope is handled in PHP.
Since that's probably not very helpful to you, I'll try to explain a better approach.
The global keyword is one of PHP's idiosyncrasies. Some people think it's dumb, but there's a certain logic to it. Lots of patterns in programming are about keeping dependencies explicit. Stuff that happens inside your class shouldn't depend on the state of the world outside. In your case (or whenever you import a global variable using global, you're coupling your class to the environment it lives in. This is bad for various reasons.
If your class requires a database connection, you should be injecting the dependency explicitly, not implicitly pulling it from global scope.
If the dependency is required for the class to function, the obvious place to inject it is in the constructor.
For example:
<?php
class MyComponent
{
/**
* #param mysqli $mysqli
*/
public function __construct($mysqli)
{
$this->mysqli = $mysqli;
}
public function getBars()
{
$bars = $this->mysqli->query('...');
return $bars;
}
}
// now back in the global scope
$mysqli = mysqli_connect('localhost', 'joe', 'secret', 'foodb');
$component = new MyComponent($mysqli);
$bars = $component->getBars();
For some project it is completely acceptable to have a single database and connection to it. Willing to access it from everywhere without using nasty global or injecting it all over the place make perfect sense.
One way I did is was simply to have my connection in a Static Object which is accessible from anywhere in my project. How I got this to work:
Use Composer to autoload my classes without having to worry about it. There are some details about how to do this here: Using Composer's Autoload
Create a class for the database connection.
class Database
{
public static $connection;
public static function connect($host, $user, $password, $database)
{
self:$connection = mysqli_connect($host, $user, $password, $database);
}
}
You can now access Database::$connection from anywhere as long as Composer includes your Database class. No need for globals...
Static classes can be quite useful for these type of usage. But some people don't like them because they are harder to test in some cases. There is no perfect solution, but do what make sense while trying to avoid bad patterns at all costs.
You may send it into constructor:
class Component {
protected $mysqli;
public function Component($mysqli = null) {
$this->mysqli = $mysqli;
}
public function foo() {
// something using $mysqli;
}
}
or set it by other methot of class after creating:
class Component {
protected $mysqli;
public function SetDBClass($mysqli)
{
$this->mysqli = $mysqli;
}
public function foo()
{
// something using $mysqli;
}
}
Use global keyword before declaration of your variable
Or put it into $GLOBALS array.
For more information about variable scope, take a look at this link: http://php.net/manual/en/language.variables.scope.php#language.variables.scope.global
Apologies for the long question. I know how to use classes, but sometimes I struggle with when to use them.
My question is three-fold really..
1) Is it good practice to always use a class method, even when the class doesn't necessarily get/set any properties?
For example, if I want a function to just spit out a HTML header, should I make this...
namespace Project1\UI;
class HTML
{
public function makeHeader()
{
echo "<html><head><title>Title</title></head><body>";
}
}
2) Do you build your own classes for things like database access, instead of calling the PDO extension directly?
The code below is adding complexity, and is really just passing values on to the PDO:
namespace Project1\DB;
use \PDO;
class Database {
private $pdo;
private $statement;
public function __construct() {
require $_SERVER['DOCUMENT_ROOT'] . 'Project1/Config/Login.php';
$pdo = new PDO(
sprintf (
'mysql:host=%s;dbname=%s;port=%s;charset=%s',
$settings['host'],
$settings['name'],
$settings['port'],
$settings['charset']
),
$settings['username'],
$settings['password']
);
$this->pdo = $pdo;
return $pdo;
}
public function prepare($statement) {
$this->statement = $this->pdo->prepare($statement);
}
public function bind($placeholder,$value) {
$this->statement->bindValue($placeholder,$value);
}
public function execute() {
$this->statement->execute();
return $this->statement->fetchAll(PDO::FETCH_ASSOC);
}
}
3) If I want to use a global function, is there good practice for where to store these on disk? Presumably I should put them in a separate file / namespace?
/Project1/Logic/Validation.php << Contains a class
/Project1/Logic/Search.php << Contains a class
/Project1/Logic/Compare.php << OK to just contain a function?
Thanks :)
Answer to 1st and 3rd questions
Yes, you may have classes that only implements functions without storing values in attributes. We call those Helpers by the way...
And no, its not a good idea to create a class for every single function you might have in your project. Keep in mind that the more files you need to include, the more reading/interpreting time your server will expend and it means a longer time to execute your script.
Answer to 2nd question
That is your call. I'd recommend extending native PDO class instead of using a Proxy Class.
PDO is a good class, you don't want to limit yourself or reinvent the wheel
I have a database class, which is used to make select, update, delete MySQL queries.
Now, I want to create a MySQL query inside another class, but if I define $db = new DB(); in index.php, I can't use the $db var in another class. Do I have to define the variable $db over and over again, if I want to make a query? Or is there a way to make the $db var with an object global var?
The cleanest approach would be to aggregate the database class where needed by injecting it. All other approaches, like using the global keyword or using static methods, let alone a Singleton, is introducing tight coupling between your classes and the global scope which makes the application harder to test and maintain. Just do
// index.php
$db = new DBClass; // create your DB instance
$foo = new SomeClassUsingDb($db); // inject to using class
and
class SomeClassUsingDb
{
protected $db;
public function __construct($db)
{
$this->db = $db;
}
}
Use Constructor Injection if the dependency is required to create a valid state for the instance. If the dependency is optional or needs to be interchangeable at runtime, use Setter Injection, e.g.
class SomeClassUsingDb
{
protected $db;
public function setDb($db)
{
$this->db = $db;
}
}
You probably want a singleton. This gives you a way to get an instance of DB anywhere in the code. Then anywhere you want to do a query, first do $db = DB::getInstance();.
An alternative is dependency injection, which passes a DB instance to all classes which need one.
Use the magic function __autoload().
First make your database class a singleton. And then in your new class you can do something like:
class myNewClass{
private $_db;
public function __construct(){
$this->_db = DB::getInstance();
}
}
Define it on a class (separate PHP file). Then require it for every PHP file the var is needed in.
In your index.php file use
require_once('path_to_file_with_class.php');
You may also use include_once, which will give you a warning instead of an error if the 'path_to_file_with_class.php' file is not available.
You might define it as global in your index.php file, and in the class constructor also put $this->db &= $GLOBALS['db'];
I'm in the process of re factoring a lot of code to make it more testable and I have a bunch of useful functions that rely on an instantiated database object.
Things like this:
function id_from_name($table, $name)
{
$db = get_database();
//code that returns an id
}
function username_from_user_id($id)
{
$db = get_database();
//code that returns a username
}
There are a bunch more like id_exists, id_active etc.
Now I'm thinking that this isn't the right thing to do as the object should probably be passed through as an argument? But then that means creating and sending in a new object into each of these functions every time i want to use one.
So really, my questions are: Should I be moving these functions into their own class/library that has access to the database object? and are the examples that I've shown above generally a bad way of doing things?
A better approach would be indeed to make classes. And you would be passing the database object to the constructor and make it an instance variable. That way every function would have access to the database object.
Now the reason why it is considered bad to instantiate e.g. your database object in every function, is because if you decide for example one day to change your datasource, you might need a huge refactor. If you pass your database object into the constructor, you can just pass/inject the right object into the class without any refactor.
...a bit more about DI below...
By passing your objects into the constructors, you also create a more clear API => you know which object depends on the other, you know exactly which class uses your DB object. If you start instantiating it or accessing it in a static way inside the functions like you did, I would have to look through all your classes to see where your DB object is used. One more point, dependency injection forces SRP (single responsibility principle) => if you start injecting too many objects (constructor gets many arguments), you should suspect your class is doing too much than what it should, and start refactoring.
You can create a class Table_Adapter and instantiate database object inside its constructor:
class Table_Adapter
{
protected $db;
public function __construct()
{
$db = get_database();
}
}
Then you create a child class Items_Table_Adapter' that extendsTable_Adapterand put their all methods related toItems` table.
class Items_Table_Adapter extends Table_Adapter
{
public function item_by_id($id)
{
}
}
Then you use it like:
$tableAdapter = new Items_Table_Adapter();
$item = $tableAdapter->item_by_id(1);
Try something like:
class YourClass{
public static function get_database(){
// your creation
return $db;
}
public function id_from_name($table, $name)
{
/* your code */
//code that returns an id
}
public function username_from_user_id($id)
{
/* your code */
}
}
so you could just use it this way:
$db = YourClass::get_database();
$result = $db->id_from_name($table, $name);
It is certainly recommended that you have the option to swap out your database connection.
Now, if your function get_database() looks like this:
function get_database() {
static $db;
if (!$db)
$db = new \mysqli(...);
return $db;
}
Then you really, really should change it to a wrapper around a class, looking like this:
function get_database_manager() {
static $dbmgr;
if (!$dbmgr)
$dbmgr = new DbManager;
return $dbmgr;
}
function get_database() {
return get_database_manager()->getCurrentConnection();
}
where DbManager has an instance attribute with the current connection that is returned with getCurrentConnection(). If you want to swapt out the connection, do something like get_database_manager()->setConnection($newConn). Problem solved :)
I'll leave the downsides of static programming here (it remains with many examples in this thread): http://kunststube.net/static/
as well as the common method to get rid of that (we have another approach here): http://en.wikipedia.org/wiki/Dependency_injection
I have a database class, which is used to make select, update, delete MySQL queries.
Now, I want to create a MySQL query inside another class, but if I define $db = new DB(); in index.php, I can't use the $db var in another class. Do I have to define the variable $db over and over again, if I want to make a query? Or is there a way to make the $db var with an object global var?
The cleanest approach would be to aggregate the database class where needed by injecting it. All other approaches, like using the global keyword or using static methods, let alone a Singleton, is introducing tight coupling between your classes and the global scope which makes the application harder to test and maintain. Just do
// index.php
$db = new DBClass; // create your DB instance
$foo = new SomeClassUsingDb($db); // inject to using class
and
class SomeClassUsingDb
{
protected $db;
public function __construct($db)
{
$this->db = $db;
}
}
Use Constructor Injection if the dependency is required to create a valid state for the instance. If the dependency is optional or needs to be interchangeable at runtime, use Setter Injection, e.g.
class SomeClassUsingDb
{
protected $db;
public function setDb($db)
{
$this->db = $db;
}
}
You probably want a singleton. This gives you a way to get an instance of DB anywhere in the code. Then anywhere you want to do a query, first do $db = DB::getInstance();.
An alternative is dependency injection, which passes a DB instance to all classes which need one.
Use the magic function __autoload().
First make your database class a singleton. And then in your new class you can do something like:
class myNewClass{
private $_db;
public function __construct(){
$this->_db = DB::getInstance();
}
}
Define it on a class (separate PHP file). Then require it for every PHP file the var is needed in.
In your index.php file use
require_once('path_to_file_with_class.php');
You may also use include_once, which will give you a warning instead of an error if the 'path_to_file_with_class.php' file is not available.
You might define it as global in your index.php file, and in the class constructor also put $this->db &= $GLOBALS['db'];