I have been advice not to use the singleton pattern for my data base class. I have not fully understand what are the cons to it, anyway there seems to be agreement in this point so I follow the rule.
But, is sharing instances of classes a bad habit in PHP in general? Which is best from the two examples provide here? I am using in fact the singleton pattern with the first approach?
//semi-pseudo Code
Class DB extends mysqli{
//
}
Class A {
$db; //Of type Class DB, initialized in the constructor.
//In some method
//Should I do this, so sharing the data base connection?
$b = new DB( $db );
// OR
// Should I instantiate a new instance?
$newDb = new DB();
$b = new B ($newDb);
}
Class B {
$db;//Of type Class DB initialized in the constructor.
I have a Class DB being a data base extension..
I have Class A with a member of type DB.
Class A needs to create an instance of Class B, which in turn also has a member of type DB.
I'm using the Dependency Injection pattern so A should pass a DB instance to B.
Should I instantiate a new DB instance to pass to B, or can I just pass a reference to A's DB instance.
There's nothing wrong with using the Singleton pattern in PHP, like any language, too much of anything likely indicates poor design.
That said, Singleton is well suited to database access. Has anyone justified why it's supposedly a bad idea?
The main argument against Singleton is difficulty to test because you can't mock them with unit test suites. Personally I try to avoid mock objects in my tests (especially w/ PHPUnit), so it usually doesn't matter.
Should I instantiate a new DB instance to pass to B, or can I just
pass a reference to A's DB instance.
Of course you have to pass a reference of A's DB instance to B class.
Related
I found myself in a situation where I'm not sure which way I should go. So far I'm using dependency injection where I pass PDO object to as a dependency.
This works quite fine, but now I need to have a Context class which would be for example holding the Info of current user. It could be something like this:
class Context
{
private $Pdo;
function __construct(PDO $Pdo) {
$this->Pdo = $Pdo;
}
function CurrentUser(){
if ($this->CurrentUser == null){
// get user logic
$this->CurrentUser = User;
}
return $this->CurrentUser;
}
}
So each time I would like to get the current user I would need to do something like this:
$Context = new Context($Pdo);
$User = $Context->CurrentUser();
I would like to be able to use this anywhere in project, but the PDO is not passed to each method there is.
I could make a singleton class for getting the PDO object anywhere I need and use that in my Context class. Would this be a good aproach? Or would a factory design be better?
Up until now I used global in such cases, but I would probably want to avoid there as the project grows rapidly.
I could make a singleton class for getting the PDO object anywhere I
need and use that in my Context class. Would this be a good aproach?
Or would a factory design be better?
Well, Singleton and Factory are not really the same thing, and your particular needs should dictate the solution.
Here is a short summary of a more in-depth post:
The Singleton pattern restricts the instantiation of a class to a single object. This provides a single point of access across the entire application, and ensure that you are always dealing with the same object.
The Factory pattern provides a new instance of the object whenever it is called. This may or may not be the same instance. Essentially the factory defines an interface for creating objects.
So, your needs will determine which pattern is better for your application. If you want a single instance of an object, go with a singleton.
Many times I heard to avoid static classes because they will insert dependencies that will render your code unusable in other projects, and will not allow to unit test it.
Let's say we have a typical class DB to access the Data Base, if such class is static we could call it wherever in our code:
DB::execQuery(...);
but this creates dependencies, so let's make the DB class NOT static, in such case we would have somewhere in our code:
$db = new DB();
and then we could call in our code
$db->execQuery(...);
But now when using the $db inside a function we need each time to first declare it like this
global $db;
Is there a way to workaround this?
One way could be to inject the $db object in the class that uses it, but I would have to inject it in all classes that use it, that's ridicolous, a static class would be much quicker to work with and less code to write. Am I missing something?!
$db could be injected upon instantiation into a property, then you would only need to access this property instead of passing it around to each method.
class MyClass {
protected $_db; // DB Connection
public function __construct($db) {
$this->_db = $db;
}
public function foo() {
$this->_db->query('...');
}
}
Beyond that, you can look into having a service-container (aka dependency-injection container) that trys to act like a global variable but solves some of the testing issues. Take a look at some of these related questions
If Singletons are bad then why is a Service Container good?
Is it good practice to have DI container replace a global $registry object?
Having a DI container lets you use static methods in your classes like DI_Container::get('db'). It looks a lot like global or some of the other static calls.. but in this case DI_Container contains special methods that allow for extra actions to be taken during testing and other circumstances.. eliminating some of the 'evilness' of global.
In addition to Mike B's answer, I would point that the wrong design in your code is : « we could call it wherever in our code ».
Actually, database should only be used by your Model, or the small part of your application that has to know about the database. So these classes should know there is a database, and use it as a dependency (passed through the constructor as Mike B said).
But the rest of your application should not care about a database, its should only care about the Model. Focus on refactoring and gathering all the code that access the database into Model classes.
This way, your application will have a Model layer that has a dependency : the database object/connection. And the rest of your application will use the Model, whatever happens in the Model in none of the Controller/View business.
Enjoy refactoring.
Writing a PHP app and have several classes that only have static methods (no need for instance methods). An example of one is NumericValidator, which has methods like checkInteger($toCheck) which checks to make sure the argument you pass it is of type int, and checkGreaterThan($lOperand, $rOperand), which makes sure that the left operand is greater than the right operand, etc.
I know I could just throw each of these methods into a PHP file without putting them inside of a class, but I want to take an OOP approach here in case the API evolves to require instantiating NumericValidator.
But it does beg the question: how is a class with 100% static methods any different than have a class implement a singleton design pattern, where every reference used throughout the code base invokes the same instance?
For example, here is what my code looks like now:
public function doSomething($p_iNum)
{
if(!NumericValidator::checkInteger($p_iNum))
// throw IllegalArgumentException
// ...
}
But I could turn all of NumericValidator's static methods into non-static instance methods, forcing the programmer to instantiate it, and then implement a singleton design pattern so you can only ever reference 1 instance of it:
public function doSomething($p_iNum)
{
NumericValidator $nv = NumericValidator::getInstance();
if(!nv->checkInteger($p_iNum))
// throw IllegalArgumentException
// ...
}
Finally, my question: which is better and more in keeping with best practices? Are there performance considerations? How would either approach affect things like concurrency, or requests coming from multiple users?
I would use a static class in your example. The differentiator I would use is if there is any state of the properties of an instance you are trying to preserve across access. This is what a singleton is designed for. The static class gives organized access to methods in a namespace which is helpful for clarity in your code but it does not have any properties about itself.
So yes you can use a singleton but it would be bad form because there are no instance properties that you want to make available across page accesses.
Hope this helps.
Use Singleton instead of static class only if you going to pass instance of NumericValidator in variable to some function.
In PHP 5.3 you can get instance of static class:
class test
{
public static function instance()
{
print 'zz';
}
}
$z = new test;
$z->instance();
Don't care about concurrency requests in PHP, it's single threaded, each process executes own code.
I'm learning myself to go from function based PHP coding to OOP. And this is the situation:
ClassA holds many basic tool methods (functions). it's __construct makes a DB connection.
ClassB holds specific methods based on a certain activity (extract widgets). ClassB extends ClassA because it uses some of the basic tools in there e.g. a database call.
In a php file I create a $a_class = new ClassA object (thus a new DB connection).
Now I need a method in ClassB. I do $b_class = new ClassB; and call a method, which uses a method from it's parent:: ClassA.
In this example, i'm having ClassA 'used' twice. Onces as object, and onces via a parent:: call, so ClassA creates another DB connection (or not?).
So what is the best setup for this basic classes parent, child (extend) situation? I only want to make one connection of course?
I don't like to forward the object to ClassB like this $b_class = new ClassB($a_object); or is that the best way?
Thanks for thinking with me, and helping :d
It doesn't look like you need the instance of class A at all. Make sure that class B really is a class A before using inheritance like this. Look into composition if you aren't sure.
From what I gather in your description, it sounds like class B should not really inherit from class A. Ask yourself - is B really an "enhanced version" of A? If not, and B is just using some utility from A, it should only call methods on it, or perhaps compose it (contain it as a member variable.)
As an aside, I don't think you should connect to the database in the constructor of A, unless you put some kind of protection around it to prevent duplicate connections. Probably better to have Connect() and Disconnect() functions so it's well understood when you are and are not connected.
$class_a = new ClassA();
$class_b = new ClassB($class_a);
class ClassB {
private $class_a;
public function __construct(ClassA $class_a) {
$this->class_a = $class_a;
}
}
If I did understand correctly what you wanted to do. This way you can ClassA methods in every method of ClassB without duplicating the connection to the database.
You could have another object that holds the Db connection that both class A and B can hook to. And its that class responsability to only make a single connection.
You could look into the singleton patter for this
I'm creating a website with structure like this:
class main { }
class mysql extends main { }
class user extends main { }
class etc extends main { }
The idea is for these classes to use functions from each other. This doesn't work. How can I call a function from mysql in user?
EDIT:
All errors are similar to this one:
Fatal error: Call to undefined method user::function_in_mysql() in C:\foo.php on line 8
Martti Laine
The idea is for these classes to use functions from each other.
That's not what you're doing: Inheritance goes only one way. mysql, user, and etc inherit mains abilities but not those of each other.
You could have mysql extend user extend etc so that at least mysql can call all the functions but that probably won't make sense, as I think they are not ancestors but siblings to each other, fulfilling a distinctly different function.
You would have to either define any shared methods in main - often the best way to go - or introduce the classes to each other so they're able to call each other's functions. You could, for example, add an instance of each needed class as parameters to the constructor:
$etc = new etc();
$mysql = new mysql($etc);
// mysql's constructor sets $this->etc
// so that it can call etc's functions using $this->etc->function()
or, more complex, using the dependency injection or singleton patterns. I asked a related question some time ago about how to deal with this in PHP and got a lot of feedback, maybe it gives you some inspiration.
Having a class extend another makes the methods of the other (parent) available to it. So user extending main only makes the methods of main available to it. If other classes extend main it doesn't allow all of them to call each others methods. You could have user extend mysql and mysql's methods would then be available to user though I don't believe that fundamentally this is what you're looking for.
I think you're looking for something along the lines of dependency injection and not class inheritance.
For example if you wanted your user class to have access to your mysql class you pass it an instance of it in it's constructor.
class user {
protected $_mysql;
public function __construct(mysql $mysql) {
$this->_mysql = $mysql;
}
public function myMethod() {
$this->_mysql->myMysqlMethod();
}
}
$mysql = new mysql();
$user = new user($mysql);
$user->myMethod();
Here's some good reading on dependency injection.
PHP Dependency Injection
Symphony Dependency Injection
The Symphony link in particular is a pretty nice read on the overview of dependency injection and how to setup a dependency container.
That's not how extending a class works. All the functions that should exist in all classes should be part of main. Then functions that are specific to mysql go in that class. I'm guessing that the classes are not as closely linked in terms of inheritance as you think. If the user class needs to make calls through your mysql class, have a variable in the user class that holds a mysql object.
To call a function from mysql inside of user you could create an mysql object inside of user and call the function.
<?php
// this is user.php
$var = new mysql(); // <--if it takes parameters in the constructor
$var->method();
...
?>
For a better answer could you provide more information, as in, what errors are you getting?