I understand the basic principles of inheritance in OOP, but I have a specific thing I am trying to do and want advice on how best to do it.
Lets say I have a core class:
class Core {
....
}
and I also have 2 or more other classes that extend this functionality
class MyClass1 extends Core {
....
}
class MyClass2 extends Core {
....
}
and I also have a database class in which I perform my queries, I want to pass an instantiated object of the database class (possibly by reference) to each one of my classes. One of the reasons for this would be to store a list or count of the queries that page as executed.
How should / can I go about this?
You could pass your instance of your database object to a constructor for your classes :
class Core
protected $db;
public function __construct(Your_Db_Class $database) {
$this->db = $database;
}
}
And, then, from your methods, work with $this->db, to access your database.
Of course, when instanciating your classes, you'll have to specify the database object :
// somewhere, instanciate your DB class
$db = new Your_Db_Class();
// And, then, when instanciating your objects :
$obj = new MyClass1($db);
Another way would be to use the Singleton design pattern, so there can be only one instance of your database class.
Probably a bit easier to setup ; but less easy to unit-test, after.
You could pass the database object as a parameter to the __construct function of your class, and then in said function assign the db object to member of the class, for instance $this->database_handler.
Another possibility is to work with a global variable that is your database object, but global variables are evil for many reasons, so let's disregard that.
Another note: By default, all objects are passed by reference, so you don't need to worry about that.
Related
In PHP, I have two classes: Database and Item.
Database contains the connection properties and methods. For example, Database::Query can be used to pass a query string, etc.
Item is a generic item identifier. It's built by passing it an itemID which is then used to query the database for the rest of the item information.
In this case, what's the best practice for creating Item objects if they require database access? Is it normal to create each one using this syntax:
$item = new Item(12345, $db);
Or is it better, acceptible, or possible to create the Database object and have it used for each Item created in the application, such that the call could become:
$item = new Item(12345);
The second seems a lot cleaner (and can be expanded so that similar types of objects don't also need that $db addon), but I'm looking for suggestions from those who have more experience at this than I do! Thanks!
I would suggest that most seasoned developers would lean toward the approach of dependency injection as demonstrated in your first example.
Why?
Well largely because this allows you to decouple the class to which the dependency is being injected from the dependency's implementation.
So consider this dependency injection example:
Class some_class {
protected $db;
__construct($db) {
if($db instanceof some_db_class === false) {
throw new Exception('Improper parameter passed.');
}
$this->db = $db;
}
}
Here you could pass any type of object so long as it was an instance of some_db_class it could be a subclass of that object that implements the same methods used by this class. That doesn't matter to this class as long as the methods are implemented (you of course could also check that a passed object implements a specific interface in addition to or in lieu of checking its instance type).
This means that, for example, you can pass a mock DB object for testing or something like that. The class doesn't care as long as the methods are implemented.
Now consider the singleton approach (or similar instantiation of DB from with the class):
Class some_class {
protected $db;
__construct() {
$this->db = some_db_class::get_instance();
}
}
Here you have tightly coupled your class to a specific database class. If you wanted to test this class with a mock DB implementation it becomes very painful in that you need to modify the class to do so.
I won't even get into discussion of using global as that is just poor practice and should not be considered at all.
I would recommend using the Singleton Pattern for your database connection. This is actually the best practice. As you really dont need to instances of your database connection.
class Database_Instance
{
private static $database;
public static function getDatabaseObject() {
if (!self::$db) {
self::$db = new PDO( );
}
return self::$db;
}
}
function callWhatSoEver()
{
$connection = Database_Instance::getDatabaseObject();
}
For more information about the singleton pattern, see: http://en.wikipedia.org/wiki/Singleton_pattern
Typically a database connection object is global, or accessible globally. That works well for the vast majority of applications.
I do something like this (simplified for example purposes):
$db = connect_to_db();
function GetDB()
{
global $db;
return $db
}
//inside the item object
function Load( $id)
{
$db = GetDB();
$db->query(..);
}
There are, of course, cases where this isn't the best route. As always, it depend on the specific needs of your application.
I have been working on moving over to OOP in PHP. I have reading explanations on php.net, but I was hoping I could get some specific answers here.
I tried to create the following example to illustrate my question. Say I have "Database", "Products", and "Users" classes, and I want to display products if a user has access.
So I call the "Products" class "showProducts()" function, which in turn creates an instance of the "User" class, which creates an instance of the "Database" object and checks the users access level.
If the user has access, then the "showProducts()" function creates another instance of the "Database" object, and queries the database.
class Database{
public function query(){
//runs query here
}
public function __construct() {
//sets up connection here
}
}
class User{
public function checkAccess(){
$db = new Database();
$db->query( //pass in query to check access )
//does stuff, then returns true or false
}
}
class Products{
public function showProducts(){
$user = new User();
if($user->checkAccess())
$db = new Database();
$db->query( //pass in query to get products )
}
}
I was hoping someone could illustrate how to do this the proper way.
I would like to have some sort of controller class, that creates one "Database" object, that is available to all of the classes that need to access it, without having to create multiple instances of the "Database" object. I would like the same thing with the users class, so there is one $users object that all the classes can access, without having to create a new object every time I need to use something in the "User" class.
I apologize if my question is not clear, and thanks in advance for any responses!!
Thanks to everybody for the replies!
When moving form procedural to Object Oriented programming you should grasp more then just how to build classes. OOP is not writing classes, its about following best practices, principles and patterns in OOP.
You should not instantiate new objects inside another, you should give the User object, his Database object that User depends on, through constructor, or setter method. That is called Dependency Injection. The goal is to give objects to a class that needs them through constructor or setter method. And they should be instanciated from outside of that class, so its easier to configure class. And when building a class you want its easy to see what dependencies that class have. You can read about Inversion of Control principle here: IoC
So then your code would look like this:
<?php
// User object that depends on Database object, and expects it in constructor.
class User
{
protected $database;
public function __construct($database)
{
$this->database = $database;
}
// -- SNIP --
}
?>
Now to use that user class you do this:
<?php
$database = new Database($connParams);
$user = new User($database);
?>
You can also use Dependency Injection using setter methods to set dependencies, but Il let you google that for yourself :)
Thats it, joust read about Inversion of Controll principle, and about Dependency Injection and Dependency Injection Containers, these are the best ways to manage classes.
I have seen lots of PHP code that is "OOP" and in fact they are only using Classes as functionality namespaces :) So joust learn about OOP principles and patterns.
Have fun! :)
Don't instantiate objects inside your constructors or other methods. Pass them as parameter, preferably inside a different class known as factory. This will make it easy to test your code, but also make it easy to create the objects.
Also, don't try to use singletons. This is the object oriented version of "global variables", and you do not want to use global variables. It makes testing of your code really hard, nearly impossible.
Watch this video http://www.youtube.com/watch?v=-FRm3VPhseI to understand why it is bad to use singletons. Especially the CreditCard example at 19:00 is worth watching.
If you really want to do it state-of-the-art, have a look at the concept of "dependency injection". Essentially, passing stuff that is needed from outside into a class is the whole secret, but there are frameworks that do this for you automatically, so you do not have to write a factory yourself anymore. These are called "Dependency Injection Container" or "DIC".
To make one object for all your code use Singleton pattern:
class Database{
private $db_descriptor;
private function __construct(){
/* connect and other stuff */
}
public static function getInstance(){
static $instance;
if($instance === null){
$instance = new self();
}
return $instance;
}
}
And you can use the same technique with users, i say more with php 5.4 you can use 1 trait for singleton pattern.
One last tip: when you work with database and other heavy things use technique called lazy initialization. When you improve your OOP skills look at Doctrine Project they use that techniques a lot!
I am not sure if this is totally the wrong thing to do, so I am looking for a bit of advice.
I have set up a database class with the constructor establishing a PDO connection to a MySQL database.
I've been looking at singletons and global variables, but there always seems to be someone who recommends against either/or.
I'm experimenting with a user class which extends the database class, so I can call upon the PDO functions/methods but maintain separate user class code. Is this a stupid thing to do?
You should generally pass a connection into your user, so your user class would take a database type object into its constructor and then use that database object to execute queries against the database. That way your data access logic remains separate from your business logic. This is called composition, as opposed to what you're talking about, which is inhertance.
If you really wanted to be technical, it would be best to have a user object with nothing but public variables, and then you would use a 'service' to implement your business logic.
class UserService implements IUserService
{
private $_db;
function __construct(IDb $db) {
$this->_db = db;
}
function GetAllUsers() {
$users = Array();
$result = $this->_db->Query("select * from user")
foreach($result as $user) {
//Would resolve this into your user domain object here
users[] = $user;
}
return users;
}
}
Well, ask yourself if User is a special case of Database. I'm not sure how others perceive it, but I would be kind of offended. I think what you need is to read about the Liskov substitution principle.
As for solving your "people tell me that globals are bad" issue, here are two videos you should watch:
The Clean Code Talks - Don't Look For Things!
The Clean Code Talks - Global State and Singletons
The idea behind class extensions in OOP is for child classes to be related to the parent classes. For instance, a school might have a Person class with extension classes of Faculty and Students. Both of the child classes are people, so it makes sense for them to extend the Person class. But a User is not a type of Database, so some people might get upset if you make it an extension.
Personally, I would send the database object as an argument to the User class in the constructor and simply assign that object to a class property. For instance:
class User
{
protected $db;
function __construct($username, $password, $db)
{
//some code...
$this->db = $db;
}
}
Alternatively, though some might yell at you for it, you can use the global keyword to inherit a variable in the global scope for use within your methods. The downside is that you would then have to declare it global in every method that needs it, or you could do:
class User
{
protected $db;
function __construct($username, $password)
{
global $db;
//some code...
$this->db = $db;
}
}
But in answer to your question, no I don't think you should make User an extension of Database; even though it would do what you need, it isn't a proper OOP practice.
It is pretty simple according to the definition of an object. It is the encapsulation of data and the operation which is performed on that data so if we only consider the theoretical point of view it would leads us in pleasurable environment.
My suggestion would be to create an abstract data access class with the generalized basic crud operations and a simple query execution using either PDO, ADO or some other database abstraction library. Now use this class as a parent for most of your model classes like the User.
Now the basic CRUD is provided by the abstract data access class and you can write the behavior specific to the user object like getting all posts for the user by consuming the simple query interface of the abstract parent class.
This approach will bring more modularity in term of coupling functionality and more readability and reuse-ability.
I don't see anything wrong with it for specific cases. You could use it for something as simple as wrapping a user's DB credentials in an object so they don't have to specify them everywhere the DB object is used.
$db = new UserDB();
would be a bit nicer than
$db = new StandarDB($username, $password, $default_db);
This article is similar to my needs, but I'm more curious about a specific solution to it, and if it's a good or bad idea to do it. Sharing objects between PHP classes
Say, like in the link above, I have an object I want to pass to multiple classes, say a $db object.
Instead of using dependency injection and passing it to each method's constructor, is it ever a good idea to let all the classes extend a Base class, that stores the $db object as a property?
For example:
abstract class Base {
protected static $_db;
public function setDatabase( Database $db ) {
$this->_db = $db;
}
public function getDatabase() {
return $this->_db;
}
}
class SomeClass extends Base {
public function doStuff() {
$result = $this->getDatabase()->query(.....);
}
}
Which would mean all classes that extend Base need not worry about grabbing/checking/setting the $db themselves, as they'd already have that object as a property as soon as the class is defined.
I know dependency injection is the usual way to go, but is this ever a viable solution?
Thanks!
You still have to set the db on each instance of the class - setting it on one instance doesnt set it on all instances... unless of course its a static property.
That is perfectly fine. I have used it before and never ran into any issues.
First of all I'm very new to OOP and I'm struggling big time. I have a question about the current design of my application and inheritance.
I have a bootstrapper file which initiates all my core classes, after including them, like this:
$security = new Security;
$error_handler = new ErrorHandler;
$application = new Application;
$mysql = new MySQL;
$template = new Template;
$user = new User;
I load the Security and ErrorHandler class first because the Application class needs them first (throw custom 404 errors, make GET variables safe etc). Now all classes extend the Application class, but I can't seem to call any data in any class from a child or parent class.
I read that I need to call the constructor of the parent class first to use any data. That's not really sexy and usefull in my eyes and I don't really see the use of using extends then.
Should I change the design? Or how could I use data from one to another class? I already tried composition but that ended up in a nightmare because I couldn't use any data of different child classes at all.
This is a weird set-up anyhow. You definitely should NOT be using some bootstrapper functionality to preload your classes, especially if certain classes have finite dependencies on other classes. What would be a bit better is this:
Your Security and ErrorHandler classes should use either static methods to allow their functionality to be used without declaring the class OR they should be created as a class var of the Application class.
class Security {
// can be invoked anywhere using Security::somefunction('blah');
public static somefunction($somevar) { ... }
}
OR
require_once('security.php');
require_once('errorhandler.php');
class Application {
public $security;
public $errorHandler;
public function __construct() {
$this->security = new Security;
$this->errorHandler = new ErrorHandler;
}
}
I'm not sure what you mean when you say that you can't access data from any class. Classes should naturally inherit any variables and functions that their parents have declared. So for example:
require_once('application.php');
class User extends Application {
public function throwError($message) {
return $this->errorHandler->somefunction($message);
}
}
Without expressly declaring $this->errorHandler from within the User class, this should still work, as the $errorHandler class var is declared in the Application class.
If you have a child-class that defines a __construct() method, and want its parent's __construct() method to be called, the __construct() method of the child class must call the parent's one.
That's the way it is in PHP ; that's what you must do ; not much of a choice.
As a reference, quoting the Constructors and Destructors section of the manual :
Parent constructors are not called
implicitly if the child class defines
a constructor. In order to run a
parent constructor, a call to
parent::__construct() within the
child constructor is required.