Sorry if I am not using the best jargon, but I have run into an issue I want to solve early before I write too much code. Which of these options below is "better"? And is there a better way of doing this? Someone mentioned to me abstracting my code but another class seems to be the last thing I need. Also I feel like there's something I can do by potentially making my "get" function seen below into a public static function so that I can use it differently. (its not static right now)
Here is my situation:
I have 2 (relevant to this question) classes, DB (database) and Page (for getting my content to display on my website)
the DB class has a query method that prepares and execute my queries
the DB class also has methods for inserting, getting, deleting things from the database.
I now feel that I may not even need my page class because right on the webpage I can just use those DB methods to call my content. (I store all images, content, page title, description in mysql). Is this not a legitimate way to do this? Won't I need to create a new object each time? such as:
$pg_ID = 2;
$title = new DB($pgID);
$title->get('pages', $pgID, $lang); // 3 tables to pull from for each page
$images = new DB($pgID);
$images->get('images', $pgID, $lang);
$structure = new DB($pgID); // I need these tables mostly because my site is in two languages
$images->get('pages_list', $pgID);
I do not like this potential solution just because to me its counter intuitive. Why should I have to create new objects just to reuse a function? However, what I do right now is something I feel is going to get me some hate mail.
$page = new Page();
$page->find('pages', $pgID, $lang);
$page->lookup($pgID);
$page->retrieve('images', $pgID, $lang);
These are 3 separate functions in my Page class that perform very similar things. Find gets my pages content out of the database and returns it as an object. Lookup does basically the same thing but only needs to pass one variable because its only to do with the html structure of each page regardless of which language is being accessed. retrieve gets all images from a table that get shown in a slider with different language descriptions. But as you can see, all three functions do basically the same thing! They query the database. Thanks for the help with this I am literally just getting into this OOP and its driving me insane. Stack has been very helpful and I think I just didn't know how to search for this to find the answer. Feel free to point me to other questions/answers that I may have missed. It was hard for me to think of the keywords to search for.
we may create other classes indeed, but efficiently so. Maybe we can render DB a public state function. I like the idea of creating a database object, pass it as parameter to an other object, which could then format data with the link he just received:
$pg_ID = 2;
$db = new DB($pg_id);
$page = new Page($db,$pg_ID);
// make sure you assign the parameters a private properties in `Page()` ctor.
then, from inside your function, you can call images, titles and structures at will from $this
$title = $this->DB->get('pages', $this->pgID, $lang);
$images = $this->DB->get('images', $this->pgID, $lang);
$structure = $this->DB->get('pages_list', $this->pgID);
and you can those other method as well
$page->find('pages', $this->pgID, $lang);
$page->lookup($this->pgID);
$page->retrieve('images', $this->pgID, $lang);
Now we do not need to create a new object each time we want information from the database.
Now...
the way I access member functions here $this->pgID is better used by defining a getter: $this->pgID(). I like my getter to have the same name as the property. This might not be a very good idea though.
private function pgID() {
return $this->pgID;
}
As for abstract classes..
I did in fact come very lately into thinking abstract classes were quite cool indeed. I've some problem with wording it, having a constant constructor with custom mandatory functions and possible different implementation of classes seems awesome:
abstract class Page {
function __construct($db,$pgID,$lang,$params='') {
$this->db = $db;
$this->pgID = $pgID;
$this->lang = $lang;
$this->init($params);
}
function pgID() {
return $this->pgID;
}
function lang() {
return $this->lang;
}
abstract function init();
abstract function retrieve();
}
class Structure extends Page {
function init($params) {
// some specific to Structure foo here
}
function retrieve($what='pages_list') {
return $this->db->get($what,$this->pgID,$this->lang);
}
}
class Image extends Page {
function init($params) {
// some specific to Image foo here
}
function retrieve($what='images') {
$images = $this->db->get($what,$this->pgID,$this->lang);
// plus some foo to resize each images
return $images;
}
}
ok, hope you're still there! Now we have a Structure and Image class with requisites constructor arguments, generic functions and a custom retrieve function. We could use them that way:
$db = new DB(2);
$template = new Structure($db,2,'fr');
$template->retrieve();
$slideshow = new Image($db,4,'en');
$slideshow->retrieve();
I do hope you do not have to create a new instance of DB if you use a different page id :-)
jokes appart this helps me using classes in a better structured way, as I might have many different classes to represent different parts of a site, but when called from an index all of them will have the same function names, like retrieve() or print(), list()...
I don't want to get into the weeds on a SPECIFIC implementation for you situation, rather I am going to offer some generic guidance.
First off, you shouldn't have to create a separate database object (dbo) for title, images, or structure. Chances are the DSN used for each dbo you are initializing are the exact same, so I would create a singleton dbo which can be shared across multiple objects. For reference take a look at Doctrine's connection manager.
Secondly, I think your objectification could be implemented better. Following most ORMS implementation, you have a Record class and a Table class. The Record class is a specific instance of a Record in your schema, whereas the Table class executes queries against your store which may result in multiple records. These results are then hydrated into an array (of records).
So what I would suggest is something like this (code has not been tested and some of it has been stubbed for brevity):
class PageTable
{
public static function getById($id)
{
// Validate id, if invalid throw exception
$dbo = Database::getConnection();
$stmt = $dbo->prepare('SELECT * FROM page WHERE id = :id');
$stmt->bindParam(array('id' => $id));
$stmt->execute();
$result = $stmt->fetch();
$page = new Page;
// Hydration
$page->setId($result['id']);
$page->setImages($result['images']);
return $page;
}
}
class Page
{
protected $id;
protected $title;
public function setId($id){}
public function getId(){}
}
Hopefully this separation of Record and methods affecting a single, or multiple records makes sense. You should take a look at a DBAL, like Doctrine.
Related
The title may be a little vague, but the question is difficult to word properly.
I'm trying to learn PHP OOP (coming from Procedural) and it's a pain - my main stump is selecting from a databased based on a certain value that is usually passed through the URL (at least in procedural).
For example, user.php?ID=2 - then I could quickly define ID using GET and future queries would use that ID.
Since my OOP classes would be in a seperate file to the main page that includes the html and outputs everything, users won't be submitting the ID to that file. In other words, they'll be going to user.php?ID=2 instead of user_c.php?ID=3 which is the class file.
My question is - how do I pass that ID through to the class? I need to select things out of the database based on the profile that they're viewing, but how do I tell the class that?
My apologies for how badly this is worded.
One would do something like this, $data now contains the data returned from the query:
//user_c.php:
Class MyUserClass {
public function getUser($id){
//Query for user data.
return $queryData;
}
}
//user.php
$userClass = new MyUserClass ();
$data = $userClass->getUser($_GET['ID']);
First of all, OOP is not that much different than procedural. The main difference is that instead of data and functions which operate on the data you have objects which encapsulate the data as well as the operations which are valid on that data.
However, in its core, OOP does encapsulate procedural programming, with the difference being that the procedural part happens within objects rather than in the application level.
To migrate from procedural to OOP all you need to do is separate your code in parts which are logically connected, in the case of databases what typically happens is each database table has a class (in MVC frameworks this is called a data model).
For example if you have a table called users you might have a corresponding User class.
class User {
private $id;
private $alsoOtherProperties;
public function __construct($dbconnection, $id) {
//Load the user from id
}
/* Setters and getters and other function here which operate on the user */
}
You then create an instance of a user which you construct from the $id given the database connection. The simplest way is do what you're already doing to get the id. From here on your data will be operating on the User object rather than on a database result. This way you don't have to worry about changing the database structure since you can just update the model to work with the new structure and the rest of the code will not need altering.
For example, say you want to update the "last logged in" column for a user at the time of log in:
//Other code around here
$ID = $db->real_escape_string(strip_tags(stripslashes($_GET['ID'])));
$user = new User($db,ID);
$user->setLastLogin(time());
$user->save();
In this example there's 2 functions defined in the class User in addition to the constructor which is to set the last login time and then update the database row which corresponds to the user. As you can see, this does not have any MySQL specific logic and the underlying code in the user class can update either a MySQL database, a text file, or not do anything (e.g. when just running tests).
Note: This is just an example, probably not a very good one at that, you should really really study OOP to learn more about it.
First and foremost you will need to create a simple database class that will handle your queries.
class DatabaseQuery {
public $parameters;
public $statement;
function __construct($statement,$parameters)
{
global $connection; //this will be your new PDO connection details
$sth = $mysqli->prepare($statement);
$sth ->execute($parameters);
$this -> executedStatement = $sth;
}
function getDetails()
{
$r_result = $this -> executedStatement;
$r_result2 = $r_result->fetch();
$show_result = $r_result2['0'];
return $show_result;
}
function executeStatementOnly()
{
return "Action Successful";
}
function __destruct()
{
//echo "Has been destroyed";
}
}
Next you will pick data from user, you will need to sanitize it using this function
function clean_data($data) {
$data = trim($data);
$data = stripslashes($data);
$data = htmlspecialchars($data);
return $data;
}
Next, pick the data and call your database query class and save or echo the data you are picking.
$get_data = clean_data($_GET["id"]);
$user_details = new DatabaseQuery("SELECT column FROM table WHERE id=?",array($get_data));
echo $user_details->getDetails();
Assuming that until now you did something like this:
// user.php
$id = $_GET['id'];
$myResult = myDbFunction($id);
function myDbFunction($id) {
// do something useful
}
you can re-write this like that:
// user_c.php:
Class MyClass {
public function myDbFunction($id) {
$something = "";
// do something useful
return $something;
}
}
// user.php:
include "user_c.php";
$myClass = new MyClass();
$id = $_GET['id'];
$myResult = $myClass->myDbFunction($id);
And that would produce the same results as if you had placed your class in the same file, like this:
// user.php:
Class MyClass {
public function myDbFunction($id) {
$something = "";
// do something useful
return $something;
}
}
$myClass = new MyClass();
$id = $_GET['id'];
$myResult = $myClass->myDbFunction($id);
I assume you know that one of the main reasons for going OOP over procedural is the re-usability as well as information hiding (i.e. sparing a user of your class the need to understand every detail of it, while still allowing them to use it)
You may want to read up on OOP with PHP, and simply play around with it. While there is a slight differece in the two styles, you should get a hang of it quickly.
Once you make sure you understood the single responsibility principle and follow it, you will surely find that OOP has many advantages over procedural programming.
I know there are loads of questions on this, I have done quite a bit of reading. I'd like to ask this in context of my project to see what suggestions you may have.
I have quite a large web application with many classes, e.g. users and articles (which i consider to be the main classes) and smaller classes such as images and comments. Now on a page, lets say for example an article, it could contain many instances of images and comments. Makes sense right? Now on say an articles page I call a static method which returns an array of article objects.
That's the background, so here are the questions.
Since building a large amount of the app I came to realise it would be very useful to have a core system class containing settings and shared functions. There for I extended all of my classes with a new core class. Seemed relatively simple and quick to implement. I know CodeIgniter does something similar. I feel now though my app is becoming a bit messy.
Question Is this a good idea? Creating an instance of core is exactly what I want when calling an instance of an article, but what about when i'm creating multiple instances using the static method, or calling multiple images or comments on a page. I'm calling the core class unnecessarily right? Really it only needs to be called once per page (for example the constructor defines various settings from the database, I don't want to this every time, only once per page obviously), but all instances of all classes should have access to that core class. Sounds exactly like I want the singleton approach, but I know that's a waste of time in PHP.
Here's an idea of what my code looks like at this point. I've tried to keep it as simple as I can.
class core {
public function __construct(){
...define some settings which are retrieve from the database
}
public function usefulFunction(){
}
}
class user extends core {
public function __construct(){
parent::__construct();
}
public function getUser($user_id){
$db = new database();
$user = /* Get user in assoc array from db */
$this->__setAll($user);
}
public static function getUsers(){
$db = new database();
$users = /* Get users from database in assoc array from db */
foreach($users as $user) {
$arrUsers[] = new self();
$arrUsers[]->__setAll($user);
}
return $arrUsers;
}
private function __setAll($attributes) {
foreach($attributes as $key => $value)
{
$this->__set($key, $value);
}
}
public function __set($key, $value) {
$this->$key = $value;
}
}
The other issue I'm having is efficiently using/sharing a database connection. Currently each method in a class requiring a database connection creates a new instance of the database, so on a page I might be doing this 5 or 10 times. Something like the dependency injection principle sounds much better.
Question Now if i'm passing the instance of the DB into the new user class, i know I need something like this...
class user{
protected $db;
public function __construct($db){
$this->db = $db;
}
... etc
}
$db = new database();
$user = new user($db);
... but when I want to run the static function users::getUsers() what is the best way to gain access to the database instance? Do i need to pass it as a variable in each static method? (there are many static methods in many classes). It doesn't seem like the best way of doing it but maybe there isn't another way.
Question If extending all of my classes off the core class as suggested in part 1, can I create an instance of the DB there and access that some how?
Question I also have various files containing functions (not oop) which are like helper files. What's the best way for these to access the database? Again i've been creating a new instance in each function. I don't really want to pass the db as a parameter to each one. Should I use globals, turn these helper files into classes and use dependency injection or something different all together?
I know there is lots of advice out there, but most info and tutorials on PHP are out of date and don't ever seem to cover something this complex...if you can call it complex?
Any suggestions on how to best layout my class structure. I know this seems like a lot, but surely this is something most developers face everyday. If you need any more info just let me know and thanks for reading!
You asked in a comment that I should elaborate why it is a bad idea. I'd like to highlight the following to answer that:
Ask yourself if you really need it.
Do design decisions for a need, not just because you can do it. In your case ask yourself if you need a core class. As you already have been asked this in comments you wrote that you actually do not really need it so the answer is clear: It is bad to do so because it is not needed and for not needing something it introduces a lot of side-effects.
Because of these side-effects you don't want to do that. So from zero to hero, let's do the following evolution:
You have two parts of code / functionality. The one part that does change, and the other part that is some basic functionality (framework, library) that does not change. You now need to bring them both together. Let's simplify this even and reduce the frame to a single function:
function usefulFunction($with, $four, $useful, $parameters)
{
...
}
And let's reduce the second part of your application - the part that changes - to the single User class:
class User extends DatabaseObject
{
...
}
I already introduced one small but important change here: The User class does not extend from Core any longer but from DatabaseObject because if I read your code right it's functionality is to represents a row from a database table, probably namely the user table.
I made this change already because there is a very important rule. Whenver you name something in your code, for example a class, use a speaking, a good name. A name is to name something. The name Core says absolutely nothing other that you think it's important or general or basic or deep-inside, or that it's molten iron. No clue. So even if you are naming for design, choose a good name. I thought, DatabaseObject and that was only a very quick decision not knowing your code even, so I'm pretty sure you know the real name of that class and it's also your duty do give it the real name. It deserves one, be generous.
But let's leave this detail aside, as it's only a detail and not that much connected to your general problem you'd like to solve. Let's say the bad name is a symptom and not the cause. We play Dr. House now and catalog the symptoms but just to find the cause.
Symptoms found so far:
Superfluous code (writing a class even it's not needed)
Bad naming
May we diagnose: Disorientation? :)
So to escape from that, always do what is needed and choose simple tools to write your code. For example, the easiest way to provide the common functions (your framework) is as easy as making use of the include command:
include 'my-framework.php';
usefuleFunction('this', 'time', 'really', 'useful');
This very simple tow-line script demonstrates: One part in your application takes care of providing needed functions (also called loading), and the other part(s) are using those (that is just program code as we know it from day one, right?).
How does this map/scale to some more object oriented example where maybe the User object extends? Exactly the same:
include 'my-framework.php';
$user = $services->store->findUserByID($_GET['id']);
The difference here is just that inside my-framework.php more is loaded, so that the commonly changing parts can make use of the things that don't change. Which could be for example providing a global variable that represents a Service Locator (here $services) or providing auto-loading.
The more simple you will keep this, the better you will progress and then finally you will be faced with real decisions to be made. And with those decisions you will more directly see what makes a difference.
If you want some more discussion / guidance for the "database class" please consider to take a read of the very good chapter about the different ways how to handle these in the book Patterns of Enterprise Application Architecture which somewhat is a long title, but it has a chapter that very good discusses the topic and allows you to choose a fitting pattern on how to access your database quite easily. If you keep things easy from the beginning, you not only progress faster but you are also much easier able to change them later.
However if you start with some complex system with extending from base-classes (that might even do multiple things at once), things are not that easily change-able from the beginning which will make you stick to such a decision much longer as you want to then.
You can start with an abstract class that handles all of your Database queries, and then constructs them into objects. It'll be easy to set yourself up with parameterized queries this way, and it will standardize how you interact with your database. It'll also make adding new object models a piece of cake.
http://php.net/manual/en/language.oop5.abstract.php
abstract class DB
{
abstract protected function table();
abstract protected function fields();
abstract protected function keys();
public function find()
{
//maybe write yourself a parameterized method that all objects will use...
global $db; //this would be the database connection that you set up elsewhere.
//query, and then pack up as an object
}
public function save()
{
}
public function destroy()
{
}
}
class User extends DB
{
protected function table()
{
//table name
}
protected function fields()
{
//table fields here
}
protected function keys()
{
//table key(s) here
}
//reusable pattern for parameterized queries
public static function get_user( $id )
{
$factory = new User;
$params = array( '=' => array( 'id' => $id ) );
$query = $factory->find( $params );
//return the object
}
}
You'll want to do your database connection from a common configuration file, and just leave it as a global variable for this pattern.
Obviously this is just scratching the surface, but hopefully it gives you some ideas.
Summarize all answers:
Do not use single "God" class for core.
It's better to use list of classes that make their jobs. Create as many class as you need. Each class should be responsible for single job.
Do not use singletones, it's old technique, that is not flexible, use dependecy injection container (DIC) instead.
First, the the best thing to do would be to use Singleton Pattern to get database instance.
class Db{
protected $_db;
private function __construct() {
$this->_db = new Database();
}
public static function getInstance() {
if (!isset(self::$_db)) {
self::$_db = new self();
}
return self::$_db;
}
}
Now you can use it like db::getInstance(); anywhere.
Secondly, you are trying to invent bicycle called Active Record pattern, in function __setAll($attributes).
In third, why do you wrote this thing in class that extends Core?
public function __construct(){
parent::__construct();
}
Finally, class names should be capitalized.
I'm trying to learn when static functions should be used, and have had a difficult time finding an answer my questions. I am creating a class User, which is related to a class Group. If I have a user id and I want to get a user object from that, is it better to do something like
$existingUser = User::get($userId);
where the class is defined like this
class User()
{
public static function get($id){
$user = new User();
return $user->findById($id);
}
public function findById($id) {
//find and populate user object
}
}
or
$existingUser=new User();
$existingUser->findById($userId);
where the class is defined like this
class User()
{
public function findById($id) {
//find and populate user object
}
}
What about if I were to write a function which returns an array of Group objects based on a user id?
class User()
{
//stuff
$groupArray = Group::getAllByUserId($this->getId())
//stuff
}
or
class User()
{
//stuff
$group = new Group();
$groupArray = $group->findAllByUserId($this->getId());
//stuff
}
The second method creates an empty group object which is never used. Does it matter?
Am I misunderstanding the concept of static? I know it is useful for not having to instantiate a class, so if the function instantiates one anyway, does that kind of defeat the purpose? If so, what would be an example of when a static function would be used?
Anything else I should be considering in this over simplified example?
You don't need a static function int he case you show above.
Static functions are really just global functions with a namespace.
Use them when the global state of the application needs to be controlled, or if multiple copies of the function lead to inonsistant results.
Callbacks sometimes need to be static, especially if they are passed as a string.
I'm trying to learn when static functions should be used
Oh, it's so simple: never.
To understand it, read:
http://www.objectmentor.com/resources/articles/ocp.pdf
http://misko.hevery.com/code-reviewers-guide/flaw-brittle-global-state-singletons/
I find a good rule of thumb is thinking "If I don't have a [class-name], would I expect to be able to call [method-name]?"
If I don't have a user, would I expect to be able to call findByID?
Probably not. This is one of the exceptions I come across; a "load" or a "save" method sometimes makes sense to be static.
A perfect example of when to use non-static methods is (most methods in) a Database class - you should always have a database object before you try to run a query on it.
An example of when to use a static method would be a "helper" class, essentially a collection of handy functions. Say you have some methods that help you output HTML, you might have HTML::image(), HTML::url() and HTML::script(). On these, you shouldn't need a HTML object to create an image, URL, and so on.
As for stopping multiple copies of objects being created (one argument for using static methods), you should use a Singleton pattern instead (Google it) to ensure only one copy of the object ever exists.
You should probably check out this question on Active Record vs data mapper:
https://stackoverflow.com/questions/2169832/data-mapper-vs-active-record
One take from this question is that static methods on the class for loading/saving aren't really the core functionality of the class in most cases. Further, storing and loading is a kind of abstract concept that is separate from your class objects in most cases.
Isa "user" a data storage and retrieval object? In most cases, no, it is a person represented in your system that has various properties and functions. When you start tying the persistence of that object into the object, you break encapsulation and make it harder to maintain the code. What if next week you want to load your users out of memcache? It's hardly relevant to if a user can have some property or functionality.
I am trying to improve the method that I am using to to database transactions in a light framework I've built.
Information to understand the question:
Here's a class I've written (where connect.php loads up database credentials; a wrapper for the PHP PDO, stored in $db; and Base.php):
<?php
require_once('connect.php');
class Advertiser extends Base
{
public static function getByID($id)
{
global $db;
$sql = "SELECT * FROM advertiser WHERE advertiserid=?";
$values = array($id);
$res = $db->qwv($sql, $values);
return Advertiser::wrap($res);
}
public static function add($name)
{
$adv = new Advertiser(null, $name);
$res = $adv->save();
return $res;
}
public static function wrap($advs)
{
$advList = array();
foreach( $advs as $adv )
{
array_push($advList, new Advertiser($adv['advertiserid'], $adv['name']));
}
return Advertiser::sendback($advList);
}
private $advertiserid;
private $name;
public function __construct($advertiserid, $name)
{
$this->advertiserid = $advertiserid;
$this->name = $name;
}
public function __get($var)
{
return $this->$var;
}
public function save()
{
global $db;
if( !isset($this->advertiserid) )
{
$sql = "INSERT INTO advertisers (name) VALUES(?)";
$values = array($this->name);
$db->qwv($sql, $values);
if( $db->stat() )
{
$this->advertiserid = $db->last();
return $this;
}
else
{
return false;
}
}
else
{
$sql = "UPDATE advertisers SET name=? WHERE advertiserid=?";
$values = array ($this->name, $this->advertiserid);
$db->qwv($sql, $values);
return $db->stat();
}
}
}
?>
As you can see, it has fairly standard CRUD functions (Edit: Okay, so only CRU, in this implementation). Sometimes, I'll extend a class like this by adding more functions, which is what these classes are intended for. For example, I might add the following function to this class (assuming I add a column isBanned to the database):
public static function getBanned()
{
global $db;
$sql = "SELECT * FROM advertiser WHERE isBanned=1";
$res = $db->q($sql);
return Advertiser::wrap($res);
}
The question:
How can I create a catchall class that will also load up custom model classes when present and necessary?
For example, if I write the following code:
$model = new Catchall();
$banned = $model->Advertiser::getByID(4);
I would expect my catchall class to modify its queries so that all the references to the tables/columns are whatever name I chose (Advertiser, in this case), but in lower case.
In addition, if I wanted to create a custom function like the one I wrote above, I would expect my catchall class to determine that a file exists in its path (previously defined, of course) with the name that I've specified (Advertisers.php, in this case) and load it.
Advertisers.php would extends Catchall and would contain only my custom function.
In this way, I could have a single Catchall class that would work for all CRUD functions, and be able to easily expand arbitrary classes as necessary.
What are the ideas / concepts that I need to understand to do this?
Where can I find examples of this already in the wild, without digging through a lot of CodeIgniter or Zend sourcecode?
What is what I'm trying to do called?
General Stuff: I would look into Doctrine2 for examples of how they make an ORM in PHP. They use mapping in a markup language to say: this table has these columns of this type. Also, while not in PHP, the Django ORM is very easy to use and understand, and working through that tutorial for 20 minutes or so will really open your eyes to some neat possibilities. (it did for me)
A quick search for "php active record lightweight" returned several interesting examples that might start you down the right path.
PHP Ideas: I would look into the magic getter and setter in php, __GET and __SET that will let you set values on your objects without having to make a getter/setter for each field of each table. You could make a single __SET that will make sure that set field is a field in that table, and add it to the list of "fields to update" next time that object is saved. BUT, this is not really a good idea long term, as it gets out of hand quickly, and is brittle.
Advice: Lastly, I worked at a company that used a system that looks almost exactly like this, and I can say unequivocally, you do not want to try to scale this long term. A system like this (the active record pattern) can save massive amounts of time up front, by not having to write queries and things, but can cost tons down the road, if you ever want to start unit testing business logic on the object classes.
For example, it is not possible to mock/dependency inject that static GetById method (it is basically a global method), so every time that is called in code, the code will go to the real database and return a real object. It doesn't take much coding like this to make a system that is almost impossible to test, snarled and tightly coupled to the database.
While they can perform a little slower than your code above, if you are planning on having this around for a considerable amount of time, try looking into ORM tools.
Edit It's called Active Record.
There are a couple different design patterns for what you are trying to do. Look into Data Mapper and Active Record.
Using PHP's "magic method" __get, you can produce this functionality, when you access it via :
$model = new Catchall();
$banned = $model->Advertiser->getByID(4);
... it will a) check to see if the class Advertiser is already defined, b) check for a file called Advertiser.php and include it, or c) return a new instance of a generic class.
The syntax you used in your example with :: assumes that the returned class is static. I have not written this code to contend with that, but it should be trivial to do so.
See the docs: http://www.php.net/manual/en/language.oop5.overloading.php#language.oop5.overloading.methods
Quick and dirty example:
public function __get($name) {
$instance = false;
// see if there is already a class with the requested name
if (class_exists($name)) {
$instance = new $name();
}
// check to see if there is an object def for the requested object
if ($instance === false && file_exists(PATH_TO_OBJECTS.$name.'.php')) {
require_once(PATH_TO_OBJECTS.$name.'.php');
$instance = new $name();
}
// if instace is still not found, load up a generic
if ($instance === false)
$instance = new Catchall($name);
return $instance;
}
I have a CORE class that pertains only to my specific site, ie, it performs site specific functions. I have a database class (for mysql), and other classes like access, validator, upload, template etc etc... I know that php classes can only extend one class each, so almost all of my classes extend the database class. I was looking over a public twitter class used on the twitter API. In it, there are functions to do almost everything you could do by going directly to the website, insert, delete, whatever... Should I put all site relatie functions inside my Core class and keep it out of the general scope of my scripts. Right now I have something like this....
Heres an example, as of right now I have functions like
$core = new Core();
$core->get_user_info($user_id);
$core->get_user_articles($user_id);
Inside that function, i perform database queries to select the needed information so i dont have to do it directly since it can get messy.
I also have functions to delete things, like
$core->Delete_Article($article_id);
However, I dont have functions to insert. Instead I use the Database class directly to add information, like so.
$article = array(user_id => $_SESSION['user_id'], body => $_POST['body']);
$db = new Database();
$db->Insert($article, 'articles');
or
$user = array(name => $_POST['name'], email => $_POST['email']);
$db->Insert($user, 'users');
Now, in the topic of separation of one aspect from another, should I put ALL of my database select/insert/update/delete queries inside my general CORE class and do ALL the database actions in the background
Like instead of $db->Insert(), i could use $core->insert_user() or just continue as I'm doing.
This is a pretty common mistake for people new to object-oriented programming. You don't want to extend a class just because it has some functions that you need. In fact, you may want to avoid extending classes at all while you're getting started. Although most intros to OOP make a big deal out of inheritance, I would steer clear for the moment.
Instead, think of how you can group together functions in terms of the way they're used. For example, say you're managing users. You need to keep track of user information, add users, delete them, etc. You could create classes like this:
class User {
function getName()...
function getID()...
}
class UserAdmin {
function addUser(User $user)...
function getUser($id)...
function deleteUser($id)...
}
These classes are organized according to concepts, not according to what functions you need to call.
When you do need reusable functions for things like database access, you'll generally want another separate object doing the work. So instead of having your UserAdmin class extend a Database class to format its SQL:
// wrong
class UserAdmin extends Database {
function getUser($id) {
$this->openConnection();
$this->runQuery("select * from users where id = {1}", $id);
}
}
... you can just use the Database class from within your UserAdmin class:
// right
class UserAdmin {
function getUser($id) {
$db = new Database();
$db->openConnection();
$db->runQuery("select * from users where id = {1}", $id);
}
}
class Database {
function openConnection() ...
function runQuery() ...
}
Initially it will seem like more work, but it keeps your various classes independent. That makes them easier to write, maintain, and test.
Because PHP is reloading everything on each page view, I do not see much advantage to instanciating classes for everything. If you break the functionality up into files that are roughly coorspond to your database schema, you can scale up and up without adding more and more functions that are loaded on each page hit.
It matters when you have dozens or hundreds of tables / classes.
Specifically for PHP, we prefer this style:
class Member
{
public static function Insert($aData)
{
//Insert member and return ID
}
public static function Select($Member_ID)
{
//select member and return Array
}
public static function List($aFilter)
{
//Return list of members filtered by specific criteria
}
}
To take it one step further, we have a static class App which holds relevant "singletonish" variables.
class App
{
public static $DB = NULL;
}
App::$DB = new Connection();
Now, anywhere in your app, you can say:
App::$DB->Query(...);
Generally, what I do is add a simple query() method to my database class which just takes SQL is an argument. Then I abstract all my general CRUD methods to the specific class. so if you have an Article class, the the deleteArticle() method would go in that class, and would extend the Article class with the database class. use $db->query($sql) within that class. and so on with your other classes...