EDIT: I got this working now. I have updated the code:
I've looked at a few examples in here, and they all look logical. But I can't get it to work. I have a class that extends my Data Access Layer (DAL). I would like to call parent class to retrieve DB results. What am I doig wrong?
DAL class
class DAL {
protected $username; // the username for db connect
protected $pwd; // the pwd to use when connecting
protected $host; // the host to which one connects
protected $dbname; // the db to select
public $conn; // reference to the db link resource
public $db; // result of db_select
public $query_result; // the stored result of the last query you ran
public function __construct()
{
$this->username = "";
$this->pwd = "";
$this->host = "";
$this->dbname = "";
}
public function connect()
{
/* connects to DB here */
}
private function query($sql)
{
/* Executes the query here and stores the result in $this->query_result */
}
public function getAllCountries()
{
$sql ="
SELECT id, name
FROM country";
//Process query
$this->query($sql);
if($this->query_result)
return $this->query_result;
}
}
And this is my other class
class myOtherClass extends DAL{
public function __construct() {
parent::__construct();
parent::connect();
}
public function getCountryListBox()
{
$result = parent::getAllCountries();
if($result)
{
$selectbox = "<select id='countryListBox' name='countryListBox'>";
while ($row = mysql_fetch_array($result))
{
$selectbox .= "<option value='".($row['id'])."'>".($row['name'])."</option>";
}
$selectbox .= "</select>";
}
else
$selectbox = "Countries could not be retrievd from database.";
return $selectbox;
}
}
This is the code in my template:
$sl = new myOtherClass();
echo '<form id="label_data_form">';
$sl->getCountryListBox();
echo '</form>';
The difference between these:
// $result = parent::getAllCountries(); // Like this
$result = this->getAllCountries(); // Or like this?
.. is probably best explained here:
class SuperFoo {
function fubar () {
echo "superfoo!";
}
function fuz () {
echo "superfuz!";
}
}
class SubBar extends SuperFoo {
function fubar() {
echo "subbar!";
}
function demonstrate() {
$this->fubar(); // "subbar!"
parent::fubar(); // "superfoo!"
$this->fuz(); // "superfuz!"
parent::fuz(); // "superfuz!"
}
}
$s = new SubBar();
$s->demonstrate();
(okay, maybe not best explained..)
Unless you particularly want the behaviour defined in the parent class, I'd always use $this->... since then you have the option of altering the behaviour if needed.
The MySQL error seems to be caused by a problem with your SQL - the class inheritance looks to be working fine.
if your class 'myOtherClass' does not implement the 'getAllCountries()' method, the following should work:
$result = $this->getAllCountries();
do not forget the $-sign before 'this'!
for the part you want to fetch list of all countries:
// $result = parent::getAllCountries(); // Like this
$result = $this->getAllCountries(); // Or like this?
the second line is correct. getAllCountries() is a method of your object, because it is inherited from your parent class. so you do not need to call the parent method. one place that you would want to call class parent's methods are in methods where you are overwriting the method.
anyways I suggest you define your properties in your DAL class as 'protected' instead of 'private'. because when you define them 'private', they can not be inherited.
so in your DAL class:
protected $username; // the username for db connect
protected $pwd; // the pwd to use when connecting
protected $host; // the host to which one connects
protected $dbname; // the db to select
you should define those properties as private, only if you do not want them to be inherited. I think your new object needs these info to connect to database.
Steven, let me draw your attention to other things, that are incorrect in your sample despite being syntactically correct. The major issue here is responsibility separation: Data Access Layer should only act as a general purpose data retrieving/storing utility class. Any additional logic should be moved outside this class.
Database connection handling should not be part of DAL. Ideal solution is to pass the db object in constructor, so the DAL operates on the connection configured somewhere else. This is called Dependency Injection and is generally regarded a good thing.
Method getAllCountries is way too specific for general purpose library. Should be replaced with getAll returning all records from current table. Table name should be passed in constructor or defined in subclass, so that every table has its corresponding DAL object.
*Method getCountryListBox generates some HTML output, which is not part of responsibility of DAL library. DAL should only return raw data.
It is worth keeping things separated, so you can reuse them in the future. Adding too many problem specific extension blurs the responsibility of a class. Main objectives of a class should be very narrow-minded, so classes can specialise in doing different things. Cooperation between several highly specialised classes should be the way of delivering complex functionality.
Generally speaking, you would use
$result = $this->getAllCountries();
(Note the **$**this rather than this!)
When calling getAllCountries from anywhere other than the getAllCountries method itself. This will ensure that if you were to override it, the overriden method would be called.
Inside the method, if you wanted to call the base class version, you would need to disambiguate the call with parent::
parent::getAllCountries();
Note you can use this form of method call within any method, but I would argue that it would be bad practice to do this by default, since it denies you the opportunity to override that method later on.
Answer to you edit?
Another typo:
but I guess you have this correct (-> in stead of -) in your code.
Are you sure the 'myOtherClass' is the 'storelocator' class?
Are you sure that storelocator is an instance of MyOtherClass? Because the method you are calling, getCountryListBox is defined in MyOtherClass, and the error complains about an undefined methods getCountryListBox...
<?php $sl = new storelocator(); ?>
<form id="label_data_form">
<?php $sl->getCountryListBox(); ?>
Update
You should add error handling logic inside query() and getAllCountries().
this->getAllCountries(); should be fine, provided that it was a type and you actually meant $this, ie with a dollar.
I'd also like to point out missing logic in getAllCountries() for cases when the query() method is returning nothing and thus $this->query_result holds nothing. getAllCountries() should return something like an empty array, because there may be cases when there's not country in the DB. You want to be able to handle that.
Related
This is my first go at creating an object oriented site in PHP and a question regarding constructors.
I have a character class that is generated after a user logs in. The character object will hold all the user data for the game.
My question is regarding the constructor / instantiating the class. Would it be okay to run a query in the class constructor like I have in the attached code?
Currently the argument being passed in is just the username which is obtained during login and that is what is ran in the query to get the character info.
Would this be okay or best practice be to run the query outside the construct or class and pass in the arguments to the classes constructor?
Just want to make sure I am not overlooking any potential issues with the current code I have - As long as exceptions are accounted for it should be okay to keep the query in the constructor, no?
<?php
include $_SERVER['DOCUMENT_ROOT']."/rx/includes/classes/connection.php";
class Character {
private $charid;
private $userid;
private $username;
private $class;
private $exp;
private $money;
private $attack;
private $defense;
private $hp;
private $turns;
function __construct($data){
$pdo = Connection::getInstance();
try {
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$char = $pdo->prepare("SELECT users.userid, users.username, characters.charid, characters.money, characters.attack, characters.defense, characters.class, characters.hp, characters.userid, characters.turns, characters.exp
FROM characters
JOIN users ON users.userid=characters.userid
WHERE username=?");
$char->execute(array($data));
$res = $char->fetchAll(PDO::FETCH_ASSOC);
$this->charid = $res[0]['charid'];
$this->userid = $res[0]['userid'];
$this->username = $res[0]['username'];
$this->class = $res[0]['class'];
$this->exp = $res[0]['exp'];
$this->money = $res[0]['money'];
$this->attack = $res[0]['attack'];
$this->defense = $res[0]['defense'];
$this->hp = $res[0]['hp'];
$this->turns = $res[0]['turns'];
}
catch (Exception $e){
echo $e;
}
}
public function __get($property) {
if (property_exists($this, $property)) {
return $this->$property;
}
}
public function __set($property, $value) {
if (property_exists($this, $property)) {
$this->$property = $value;
}
return $this;
}
}
No.
And it is also advised to avoid using magic setters and getters. And same goes for singletons.
A constructor shouldn't actually contain any logic, because it make the code quite hard to test. Instead your class constructor should expect the connection as a parameter and perform the logic in a separate method. Kinda like this:
class Character
{
private $connection;
public function __construct(\PDO $pdo)
{
$this->connection = $pdo;
}
public function populateByUsername($data)
{
// come code
$statement = $pdo->prepare("SELECT us ....");
$statement->execute(array($data));
$data = $char->fetchAll(PDO::FETCH_ASSOC);
// more code
}
}
To improve the code further, I would recommend actually separating the SQL code from the entity's logic (in your example - character). The best approach for that would be use of data mapper pattern - it basically means that you have two classes - one for entity and one for sql parts. It ends up looking kinda like this:
$char = new Character;
$char->setUsername($username);
$mapper = new CharacterMapper($pdo);
$mapper->fetchByUsername($char);
In this case the mapper class take your entity, uses a getter to extract the username, calls the SQL and then puts the data in the character object. Later, when you get more familiar with OOP, you will also learn to be able to call multiple mapper on the same entity, when necessary (for example, you can set it up so that there is a separate mapper for cache and separate for db .. you call the cache mapper first, and if it fails, you call the db mapper).
The downside with this is your 'Character' class constructor would be tightly coupled to your database. Which means there would be no other way to initialize your 'Character' except with getting data from the DB. You won't be able to initialize it with another source (e.g. XML files) or initialize it with test data for the purposes of unit testing.
What I would recommend is to separate the query, into something like a 'InitializationProvider' (it's just an example because I'm not sure about your app's logic). Then you could have different types of InitializationProviders like DBInitializationProvider, XMLInitializationProvider, etc. that would be dynamically injected into your Character class.
It's up to you though if that kind of flexibility would be required in the future.
Second update
I think I've been approaching this problem from the wrong side of the coin. Would I be correct in assuming that I should be making 'First' an abstract class and just finding a way to reference 'Second' and 'Third' at a later time?
Update
Based on some of the feedback, I have added some content to try and clear up what I would like to do. Something similar to this effect.
I know from just looking at the code below that, it is a waste of performance "if" it did work and because it doesn't, know I am approaching the problem from the wrong angle.The end objective isn't all to uncommon at a guess from some of the frameworks I've used.
I'm more trying to base this particular bit of code on the CodeIgniter approach where you can define (what below) is STR_CLASS_NAME in a config file and then at any point through the operation of the program, use it as i have dictated.
STR_CLASS_NAME = 'Second';
class First {
protected $intTestOne = 100;
public function __construct() {
$strClassName = STR_CLASS_NAME;
return new $strClassName();
}
public function TestOne() {
echo $this->intTestOne;
}
protected function TestThreePart() {
return '*Drum ';
}
}
class Second extends First{
/* Override value to know it's working */
protected $intTestOne = 200;
/* Overriding construct to avoid infinite loop */
public function __construct() {}
public function TestTwo() {
echo 'Using method from extended class';
}
public function TestThree() {
echo $this->TestThreePart().'roll*';
}
}
$Test = new First();
$Test->TestOne(); <-- Should echo 200.
$Test->TestTwo(); <-- Should echo 'Using method from extended class'
$Test->TestThree(); <-- Should echo '*Drum roll*'
You may be asking, why do this and not just instantiate Second, well, there are cases when it is slightly different:
STR_CLASS_NAME = 'Third';
class Third extends First{
/* Override value to know it's working */
protected $intTestOne = 300;
/* Overriding construct to avoid infinite loop */
public function __construct() {}
public function TestTwo() {
echo 'Using method from extended class';
}
public function TestThree() {
echo $this->TestThreePart().'snare*';
}
}
$Test = new First();
$Test->TestOne(); <-- Should echo 300.
$Test->TestTwo(); <-- Should echo 'Using method from extended class'
$Test->TestThree(); <-- Should echo '*Drum snare*'
Situation
I have a an abstract class which extends a base class with the actually implementation; in this case a basic DB wrapper.
class DBConnector ()
class DBConnectorMySQLi extends DBConnector()
As you can see, MySQLi is the implementation. Now, dependant upon a value in the configuration process, a constant becomes the class name I wish to use which in this case (as shown below builds DBConnectorMySQLi.
define('STR_DB_INTERFACE', 'MySQLi');
define('DB_CLASS', 'DBConnector'.STR_DB_INTERFACE);
Objective
To have a base class that can be extended to include the implementation
For the code itself not to need know what the name of the implementation actually is
To (in this case) be able to type or use a project accepted common variable to create DBConnectorMySQLi. I.E. $db or something similar. W
Issue
When it comes to actually calling this class, I would like the code to be shown as below. I was wondering whether this is at all possible without the need to add any extra syntax. On a side note, this constant is 100% guaranteed to be defined.
$DBI = new DB_CLASS();
Solution 1
I know it is possible to use a reflection class ( as discussed in THIS QUESTION) and this works via:
$DBI = new ReflectionClass(DB_CLASS);
However, this creates code that is "dirtier" than intended
Solution 2
Start the specific implementation of DBConnectorMySQLi within the constructor function of DBConnector.
define('STR_DB_INTERFACE', 'MySQLi');
define('DB_CLASS', 'DBConnector'.STR_DB_INTERFACE);
class DBConnector() { public function __construct() { $this->objInterface = new DBConnectorMySQLi(); }
class DBConnectorMySQLi()
This however would result in the need to keep on "pushing" variables from one to the other
Any advice is much appreciate
You can use variables when you instantiate a class.
$classname = DB_CLASS;
$DBI = new $classname();
Source: instantiate a class from a variable in PHP?
I'm struggling to find a correct approach to pass data between classes, which do not directly call each other, and are only related through a parent class (which I now use, but I consider it a dirty workaround rather than anything near a solution).
I have 3 classes both able to read input and write output, and based on configuration I set one to read, another one to write. It may even be the same class, they all share a parent class, but they are always two separate instances called from a controller class.
Currently I use this sort of functionality:
class daddy {
public static $data;
}
class son extends daddy {
public function setData() {
parent::$data = "candy";
}
}
class daughter extends daddy {
public function getData() {
echo parent::$data;
}
}
while($processALineFromConfig)
$son = new son;
$son->setData();
$daughter = new daughter;
$daughter->getData();
daddy::$data = null; //reset the data, in the actual code $daughter does that in parent::
}
Instantination of these classes runs in a loop, therefore I always need to reset the data after $daughter receives them, 'cos otherwise it would stay there for another pass through the loop.
I'm absolutely sure it's not how class inheritance is supposed to be used, however I'm struggling to find a real solution. It only makes sense the data should be stored in the controller which calls these classes, not the parent, but I already use return values in the setter and getter functions, and I am not passing a variable by reference to store it there to these functions 'cos I have optional parameters there and I'm trying to keep the code clean.
What would be the correct approach to pass data through the controller then?
Thanks!
The best option would be for two object share some other, third object. This would be the class for "third object" which will ensure the exchage:
class Messenger
{
private $data;
public function store($value)
{
$this->data = $value;
}
public function fetch()
{
return $this->data;
}
}
Then a class for both instance, that will need to share some state:
class FooBar
{
private $messenger;
private $name = 'Nobody';
public function __construct($messenger, $name)
{
$this->messenger = messenger;
$this->name = $name;
}
public function setSharedParam($value)
{
$this->messenger->store($value);
}
public function getSharedParameter()
{
return $this->name . ': ' . $this->messenger->fetch();
}
}
You utilize the classes like this:
$conduit = new Messenger;
$john = new FooBar($conduit, 'Crichton');
$dominar = new FooBar($conduit, 'Rygel');
$dominar->setSharedParameter('crackers');
echo $john->getSharedParameter();
// Crichton: crackers
Basically, they both are accessing the same object. This also can be further expanded by making both instance to observe the instance of Messenger.
I am coding my first object factory, and I am wondering if there any any drawbacks to passing one object into another when creating the second object, and then saving the first object within the second for use later?
Example:
class main
{
public $connection = array();
// various other useful functions that should be loaded on every page here
// these other functions would be convenient to have avail for
// new objects in different classes
function dbconnect($db) {
if(!isset($this->connection[$db])) {
switch($db) {
case "users":
$connection = #mysql_connect(info,info,info);
$db_select = #mysql_select_db(info,$connection);
$this->connection[$db] = $connection;
break;
case "ads":
$connection = mysql_connect(info,info,info);
$db_select = mysql_select_db(info,$connection);
$this->connection[$db] = $connection;
break;
default:
die($db . " is not a recognized database.");
break;
}
}
return $this->connection[$db];
}
// note how i pass $this into the new object in this function
function create($class,$params=null) {
if(!class_exists($class) && !$this->load($class)) {
die($class . " is not a recognized class.");
}else{
return new $class($this,$params);
}
}
function load($file) {
$file = $_SERVER['DOCUMENT_ROOT'] . "/classes/" . $file . ".class.php";
if(file_exists($file)) {
return require_once($file);
}else{
return false;
}
}
}
class secondary {
private $connection;
private $mainObj;
private $params;
function __construct($mainObj,$params) {
$this->mainObj = $mainObj;
$this->params = $params;
$this->connection = $mainObj->dbconnect('users');
}
}
As you see here, any class created by the factory conveniently has the ability to connect to the MySQL db if the class requires it (and other common/useful functions) ... without having to use globals, or pass many things in.
Is this a stable way? I am new, and could use some good theory/schooling on why this is wrong - if it is.
Yes, it is a pretty stable way. But I would like to see type hinting in the methods taking outer instances as parameters, which would make your classes typed stronger.
Example;
class Alob {
public function aMethod(**Blob** $outerObject) {
...
}
}
class Blob {
...
}
This will throw a fatal error if Alob::aMethod() is called with another type than Blob.
I would also like to see more accessor keywords for defining visibility, hide your class privates with 'private' and so on.
Definitely nothing wrong with object passing. If you have a ClassB object that needs an instantiated object of ClassA in order to function, then your only options are to create that ClassA object inside ClassB, or to pass ClassA in.
If the ClassA object is likely to be used by multiple ClassB objects, like in your example, then passing the ClassA (ie. Database connection object) around is actually more efficient than the alternative, which would involve a lot of duplicate objects being created inside each class.
Since PHP5 automatically passes objects by reference, setting up a reference inside your secondary class to $mainObj is actually very efficient.
One this you'll have to be careful with, with that solution of keeping an object accessing the DB (which is not bad ; you should read about the "Dependancy injection" pattern, btw), is to not disconnect from the DB as long as you still need to be able to access it
(Yeah, seems pretty logical ^^ )
What I mean is it might become easy to forget that some object somewhere needs the DB connection not to be closed.
Easy way would be to never disconnect -- PHP will automatically close the connection to the DB server at the end of the script, anyway.
Not only is this ok, but it's actually one of the cornerstones of OOP, and it's called aggregation
A couple of the options are:
$connection = {my db connection/object};
function PassedIn($connection) { ... }
function PassedByReference(&$connection) { ... }
function UsingGlobal() {
global $connection;
...
}
So, passed in, passed by reference, or using global. I'm thinking in functions that are only used within 1 project that will only have 1 database connection. If there are multiple connections, the definitely passed in or passed by reference.
I'm thining passed by reference is not needed when you are in PHP5 using an object, so then passed in or using global are the 2 possibilities.
The reason I'm asking is because I'm getting tired of always putting in $connection into my function parameters.
I use a Singleton ResourceManager class to handle stuff like DB connections and config settings through a whole app:
class ResourceManager {
private static $DB;
private static $Config;
public static function get($resource, $options = false) {
if (property_exists('ResourceManager', $resource)) {
if (empty(self::$$resource)) {
self::_init_resource($resource, $options);
}
if (!empty(self::$$resource)) {
return self::$$resource;
}
}
return null;
}
private static function _init_resource($resource, $options = null) {
if ($resource == 'DB') {
$dsn = 'mysql:host=localhost';
$username = 'my_username';
$password = 'p4ssw0rd';
try {
self::$DB = new PDO($dsn, $username, $password);
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
}
} elseif (class_exists($resource) && property_exists('ResourceManager', $resource)) {
self::$$resource = new $resource($options);
}
}
}
And then in functions / objects / where ever:
function doDBThingy() {
$db = ResourceManager::get('DB');
if ($db) {
$stmt = $db->prepare('SELECT * FROM `table`');
etc...
}
}
I use it to store messages, error messages and warnings, as well as global variables. There's an interesting question here on when to actually use this type of class.
Try designing your code in an object-oriented fashion. Methods that use the database should be grouped in a class, and the class instance should contain the database connection as a class variable. That way the database connection is available to the functions that need it, but it's not global.
class MyClass {
protected $_db;
public function __construct($db)
{
$this->_db = $db;
}
public function doSomething()
{
$this->_db->query(...);
}
}
I see that a lot of people have suggested some kind of static variable.
Essentially, there is very little difference between a global variable and a static variable. Except for the syntax, they have exactly the same characteristics. As such, you are gaining nothing at all, by replacing a global variable with a static variable. In most examples, there is a level of decoupling in that the static variable isn't referred directly, but rather through a static method (Eg. a singleton or static registry). While slightly better, this still has the problems of a global scope. If you ever need to use more than one database connection in your application, you're screwed. If you ever want to know which parts of your code has side-effects, you need to manually inspect the implementation. That's not stuff that will make or break your application, but it will make it harder to maintain.
I propose that you chose between one of:
Pass the instance as arguments to the functions that needs it. This is by far the simplest, and it has all the benefits of narrow scope, but it can get rather unwieldy. It is also a source for introducing dependencies, since some parts of your code may end up becoming a middleman. If that happens, go on to ..
Put the instance in the scope of the object, which has the method that needs it. Eg. if the method Foo->doStuff() needs a database connection, pass it in Foo's constructor and set it as a protected instance variable on Foo. You can still end up with some of the problems of passing in the method, but it's generally less of a problem with unwieldy constructors, than with methods. If your application gets big enough, you can use a dependency injection container to automate this.
My advice is to avoid global in the bulk of the code - it's dangerous, hard to track and will bite you.
The way that I'd do this is to have a function called getDB() which can either be at class level by way of a constructor injection or static within a common class.
So the code becomes
class SomeClass {
protected $dbc;
public function __construct($db) {
$this->dbc = $db;
}
public function getDB() {
return $this->dbc;
}
function read_something() {
$db = getDB();
$db->query();
}
}
or using a common shared class.
function read_something() {
$db = System::getDB();
$db->query();
}
No matter how much elegant system design you do, there are always a few items that are necessarily global in scope (such as DB, Session, Config), and I prefer to keep these as static methods in my System class.
Having each class require a connection via the constructor is the best way of doing this, by best I mean most reliable and isolated.
However be aware that using a common shared class to do this can impact on the ability to isolate fully the objects using it and also the ability to perform unit tests on these objects.
None of the above.
All the mysql functions take the database connection argument optionally. If you leave that argument out, the last connection by mysql_connect() is assumed.
function usingFunc() {
$connection = getConnection();
...
}
function getConnection() {
static $connectionObject = null;
if ($connectionObject == null) {
$connectionObject = connectFoo("whatever","connection","method","you","choose");
}
return $connectionObject;
}
This way, the static $connectionObject is preserved between getConnection calls.