The Situation
I have a table in a DB that contains job types, basically defined by a label and a price. I'm trying to do a simple SELECT * FROM jobtype but I can't seem to get it to work, although I've use the same block over and over again in the rest of the code. The main difference here, is that it is a singleton trying to execute the function.
The problem is that as soon as I uncomment the line $rs_job_types = mysql_query($query_job_types, $vtconnection) or die(mysql_error()); the page will stop loading at this particular point in the code.
The Code
Following is the code of my function getJobTypes():
require_once('Connections/vtconnection.php');
class JobTypes extends Singleton{
static private $job_types;
public static function getJobTypes(){
if (self::$job_types == null){
echo 'DEBUG: For now, $job_types is NULL.'."\n";
mysql_select_db($database_vtconnection, $vtconnection);
$query_job_types = 'SELECT * FROM jobtype';
$rs_job_types = mysql_query($query_job_types, $vtconnection) or die(mysql_error());
while ($rs_row = mysql_fetch_assoc($rs_job_types)){
// let the job type identifier in the db be its index in our array
self::$job_types[$rs_row['id']]['label'] = $rs_row['label']; // job type label
self::$job_types[$rs_row['id']]['price'] = $rs_row['price']; // job type price
}
if (self::$job_types != null) echo 'DEBUG: $job_types has been populated.'."\n";
}
return self::$job_types;
}
}
Which I am calling like so:
$jt = JobTypes::getJobTypes();
Here is my singleton pattern:
class Singleton{
private static $instances = array();
final private function __construct(){
}
final public function __clone(){
trigger_error('You don\'t clone a singleton!', E_USER_ERROR);
}
final public static function getInstance(){
$c = get_called_class();
if(!isset(self::$instances[$c])){
self::$instances[$c] = new $c;
}
return self::$instances[$c];
}
}
I have turned the problem in my head, commented everything inside the getJobtypes() function and uncommented step by step. I found out the problem does happen with the mysql_query() line, just can't seem to work out why. Is something obviously wrong in my code?
Solved
As suggested here, I used global $vtconnection,$database_vtconnection; at the start of my static function and all went smooth. It is not an optimal solution but it pointed out the scope issue which I will now try to resolve.
I also got rid of the singleton pattern.
Well the most obvious thing is $database_vtconnection $vtconnection are defined nowhere in your getJobTypes function. If they're part of the class, you need $this (object) or self (static) references. More likely it looks like you're trying to use global variables, in which case you have to pull them into the scope of the function.
mysql_select_db can auto-connect (if $vtconnection isn't supplied) but only if it knows how - there's a previous connection (or possible INI config with db/host/user/pass).
To pull them into scope you need to add the line at the beginning of the function:
global $vtconnection,$database_vtconnection;`
... Or use the $GLOBALS superglobal array:
mysql_select_db($GLOBALS["database_vtconnection"],$GLOBALS["vtconnection"]);
For the record using globals isn't a particularly good solution.
Related
This is an odd situation and I think the answer is 'you can't do that, what are you thinking?' but hope someone can prove me wrong.
My goal is to store a globally scoped function in a variable then inject it for execution within a class object.
I would like to avoid using call_user_func() as this searches for the function in the global namespace and is the same effect as if I were to just execute the global function from within the class object. I would like my class to execute the object as if it were an internal class method, not an external function. This comes close but not quite.
I cannot modify the function or wrap it in a class.
(Why am I jumping through these hoops?) Needs to be used within this class to follow a spec.
I know I can just duplicate the function in the class and be done with it, but you know the issues with that (plus it creeps up on SRP.) Reflection would work perfectly but this function is not in a class, it is just out there in an include. I've tried wrapping it an anonymous function and the closure object doesn't execute the function.
Is there any hope to do this? The function is simple, accepts a scalar param, does some stuff to it, returns a value (and is tightly coupled with other code, cannot be moved or changed.)
function someFunction($param)
{
// do some stuff
return $someScalarValue;
}
What I would hope is something like
$func = someFunction([some value]); // doesn't work of course, this would store result in $func
$cls = new SomeClass($func);
Then a method in the class could run the function object, much like call_user_func but not have to search the global namespace.
protected function someThing()
{
$this->injected_function([some class value]); // also doesn't work of course
}
When you use $this you are in the objects instance scope. You could pass a (reference) method into the constructor.
$myFunc = function($arg) { var_dump($arg); return 314; };
class myClass {
private $func;
public function __construct($func) {
$this->func = $func;
}
public function do($value) {
$this->func->call($this, $value);
}
}
$var = 'Hello world!';
$myObj = new myClass($myFunc);
$value = $myObj->do($var); // $value is now 314
If you do not want the function to be stored in global namespace you can just pass even an anonymous function like this on the fly:
$myObj = new myClass(function($arg) { var_dump($arg); return 314; });
$value = $myObj->do($var); // $value is now 314
Thank you #Markkus Zeller for your comments, as I suspected there is no way to do what I originally was tasked, to "inject" a global function as an dependency. There is, but it only really works with anonymous functions.
After a lot of stressful pushback, I convinced our managers that wrapping this in a simple class was the way to go. This,
// require_once('some-function.php');
function someFunction($param)
{
// do some stuff
return $someScalarValue;
}
. . . now becomes this. (Typed out on the fly and may contain deficiencies, concept only)
// require_once('some-function.php');
require_once('path/to/SomeFunctionClass.php');
function someFunction($param)
{
$cls = new SomeFunctionClass($param);
return $cls->execute();
}
. . . where execute() contains identical code that was in someFunction(). I can now use "SomeFunctionClass" for a DI. There is more to the story, but that is the gist, and this one change can be implemented without modifying any of the 450 or so instances that use this global function (and each of those they can be gradually ported to use the new wrapper.) It also allows me to isolate and mock the functionality for unit testing.
Before anyone says anything. I've been to many articles, and I just can't wrap my head around the purpose of a constructor.
I've found an example on a site. Here's the code:
<?php
class dogtag {
public $Words;
}
class dog {
public $Name;
public $DogTag;
public function bark() {
print "Woof!\n";
}
public function __construct($DogName) {
print "Creating $DogName\n";
$this->Name = $DogName;
$this->DogTag = new dogtag;
$this->DogTag->Words = "My name is $DogName. If you find me, please call 555-1234";
}
}
class poodle extends dog {
public function bark() {
print "Yip!\n";
}
}
$poppy = new poodle("Poppy");
print $poppy->DogTag->Words . "\n";
?>
It echoes out the following:
Creating Poppy My name is Poppy. If you find me, please call 555-1234
May someone please explain this code to me like I'm 5. I just don't get it.
A constructor is used to do any initial process required once a new class object was initiated. Ok so that was pretty fancy right? Lets break down what that means with an example. Lets first make a class, and inside that class put some variables, some functions, and a constructor! (It's easier for me to explain the concept behind a constructor with a simpler class. babysteps.)
<?php
class myInfo
{
protected $limit;
public function __construct($limit = 10)
{
$this->limit = $limit;
}
public function awesomesauce() {
//...some random code...
}
}
$variable = new myInfo();//initiating an instance of class myInfo
?>
The code $variable = new myInfo(); is initiating an object of type myInfo. When that initiation happened, the php code knows that right away, the constructor function public function __construct($limit = 10) has to be called. In this case, the value of $limit is made to be 10. However, if I later on do the following code:
$variableTwo = new myInfo(20);
The variable passed inside the parenthesis would be passed directly into the constructor function.
So depending on the specific situation I could either pass no variables when creating an instance of type myInfo, in which case the constructor function would use the default value of ($limit = 10) or I could pass a value. If php did not have the ability to use constructors, I would literally have to manually change that variable with a new line of code every time I initiated a new object of class myInfo. Now this is just a simple example. Imagine if you need to not only initiate values, but run functions that work with API's somewhere else on your server. You can definitely see the benefit of having this happen automatically instead of being forced to write multiple lines of code every single time an object is initiated.
Let me know if that helped.
I'm trying to build a View class for Smarty templates so I could call templates like in Laravel View::make('template');
But, for first time I'm getting this error. I found plenty of responses fixing the issue but I cannot fix mine. I don't know why so I'm starting to be little bit fed up... hehehehe
This is the class:
class View {
public $engine;
protected $tmpl_folder = 'tmpl';
protected $tmpl_compiled = 'tmpl_c';
protected $cache = true;
protected $force = true;
function __construct() {
$this->engine = new Smarty();
$this->engine->compile_check = $this->cache;
$this->engine->force_compile = $this->force;
$this->engine->template_dir = './' . $this->tmpl_folder . '/';
$this->engine->compile_dir = './' . $this->tmpl_compiled;
}
static function make($t, $args = '') {
if(!empty($args))
$this->engine->assing($args);
$this->engine->display($t.'.tpl');
exit();
}}
Error is launching in method make(), line <b>$this->engine->assing($args)</b>.
I tried to change declaration of $engine variable to public, private, protected and static... nothing...
I declared make() like public, public static, like in the example above and the same with no "static".... nothing...
I tried to change $this-> for self::... nothing...
I don't know what else can I do! Some advice please!
to get this working quickly instantiate your View class as an object like this:
$obj_view = new View();
then make your call to the make() method like this:
$obj_view->make('template');
I'd also declare scope for your methods (functions) (both of them should be public) - you did it for the properties (variables), so why not for the methods as well and remove static from the make()
why are you calling exit() in make()? I hope this is for debug ('Dead programs tell no lies')
assing() made me lol, a great typo! :)
TIP: avoid using bad language in code (in variable names, comments or debug) these are viewable by other developers and can, unintentionally, leak to the end user - it's not professional!
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?
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.