Calling objects of other class in php? - php

I am working on a website with php/mysql.
I have 3 files config.php, utils.php and member.php. code of the files are as below,
config.php - $objPath->docrootlibs is fine, I am sure there is no problem with this.
/* Other library files & their object */
require($objPath->docrootlibs.'/utils.php');
$objUtils = new utils();
require($objPath->docrootlibs.'/member.php');
$objMember = new member();
utils.php
class utils{
function getCurrentDateTimeForMySQL(){
return date("Y-m-d H:i:s");
}
}
members.php
class member{
var $userid;
var $username;
function __construct(){
$this->lastactivity = $objUtils->getCurrentDateTimeForMySQL();
}
}
Now when I am including the config.php inside a page home.php with simple php include statement and running that page then it gives me following error.
Notice: Undefined variable: objUtils in D:\wamp\www\site\libs\member.php on line 17
Fatal error: Call to a member function getCurrentDateTimeForMySQL() on a non-object in D:\wamp\www\site\libs\member.php on line 17
Line numbers in error above are different, I just copied the specific part from the code here.
I am not understanding why its giving error, because objects of utils class is defined on config page before including the member class. It should detect that object.
Please check and help me to understand and correct this error.
Thanks!

One Solution
Unlike JavaScript PHP will not bubble up through scopes, which means
public function __construct(){
$this->lastactivity = $objUtils->getCurrentDateTimeForMySQL();
}
does not know what $objUtils is, because there is no such object defined in the local scope. This means, you have to make the object available inside that scope. The cleanest and most maintainable way to do that is to inject the utils instance to the member instance, e.g.
public function __construct($utils){
$this->lastactivity = $utils->getCurrentDateTimeForMySQL();
}
However, since you seem to be using that value on construction only anyway, there is no reason why your member instance has to know how to use the utils object. So why not just insert the actual value right from the start, e.g.
public function __construct($lastActivity){
$this->lastactivity = $lastActivity;
}
// then do
$utils = new utils();
$member = new member($utils->getCurrentDateTimeForMySQL());
On globals
You definitely do not want to use the global keyword or static methods. Both couple back to the global scope. This means you can no longer use the member class without the global scope. This makes maintaining, reusing, refactoring and testing harder. OOP is about encapsulation and by reaching out from the class to the global scope you are breaking that encapsulation. Use Dependency Injection as shown above instead.
Apart from that, using globals will also make your code harder to read. A developer looking at the ctor signature of member is likely to assume there is nothing else to do than just call new member. That's a lie, because she also has to setup the utils instance. In other words, you are hiding dependencies. The developer has to look at the actual code to understand what's going on. Thus, make dependencies explicit.
Some more resources:
http://c2.com/cgi/wiki?GlobalVariablesAreBad
http://misko.hevery.com/code-reviewers-guide/flaw-brittle-global-state-singletons/
EDITs after comments
If you really need that utils object, inject the instance and assign it to a property inside the member instance in the ctor. Then you can access it with $this->utils->foo() from anywhere else inside the member instance.
However, Utility classes are almost always a sign of bad design. It is much more likely that they should be broken apart and divided into/onto other objects. Try to find out the reponsibilities. Maybe Member should not use Utils, but Utils should be something else that uses Members.
Out of curiosity, why do you need a utility method for MySql anyway? If you use a Timestamp column in MySql for lastActivity, it will automatically update whenever the row is updated. I am assuming you are setting the lastActivity and then store the member data?
Regarding performance: you should not bother about performance. Write readable and maintainable code first and foremost. If you think your performance is not good enough, profile the application with XDebug to see what is really making an impact.

As another comment states, use dependency injection. Insert the utilities object into the constructor. Do not introduce variables over the global scope, especially between different files. This gets very confusing and creates a mandatory order of some file includes.
class member {
...
public function __construct(utils $objUtils) {
$this->objUtils = $objUtils;
...
}
}
In calling code:
$member = new member(new utils);
As an aside, I find it humorous that you have a macro with a name that is longer than the operation it performs.
As another aside, do you need a utilities class? Can the utilities just be functions?

It sounds like config.php is in the global scope. You need to use the global keyword when using $objUtils
function __construct(){
global $objUtils;
$this->lastactivity = $objUtils->getCurrentDateTimeForMySQL();
}

Since your getCurrentDateForMySQL doesn't depend on anything else inside your utils object, why not make it a static function? That way you can turn your member() method into:
function __construct(){
$this->lastactivity = utils::getCurrentDateTimeForMySQL();
}

Related

Are static functions any better than globals? [duplicate]

I'm creating a basic framework in PHP. I need to pass data for the current page into different functions, allow them to modify and save it, and then pass it back to the page to be displayed. I was originally planning on storing the data in a global variable like $GLOBALS['data'], but I'm starting to think that using a global is a bad idea. So I'm thinking that instead I will put a static variable in the system class, and access it using system::$data. So, my question is, which would be better and why?
This:
$GLOBALS['data'] = array();
$GLOBALS['data']['page_title'] = 'Home';
echo $GLOBALS['data']['page_title'];
Or this:
class system
{
public static $data = array()
}
function data($new_var)
{
system::$data = array_merge(system::$data, $new_var);
}
data(array('page_title' => 'Home'));
echo system::$data['page_title'];
There really is no difference between a global variable and a public static variable. The class variable is namespaced a tiny bit better, but that hardly makes any difference. Both are accessible anywhere at any time and both are global state.
As it happens, I just wrote an exhaustive article on the subject:
How Not To Kill Your Testability Using Statics
So, my question is, which would be better and why?
You already sense that there is some problem putting this all into globals. Although you have developed some thoughts to encapsulate things into a class.
I think that is a good starting point. Let's add some more spice to the cooking to get this more fluent at the beginning:
$data = new ArrayObject(array());
$data['page_title'] = 'Home';
You have created an object now that you can pass along containing your data. Just pass $data to the area's where it's needed. No global or global static variable needed.
You can even make that type more concrete later on by extending from ArrayObject with your own type.
For the record.
Pro of static:
Clarity of the code. For example:
function fn() {
System::data()
}
versus
function fn() {
global $system;
$system->data()
}
Cons of static:
If you are using psr-4 then you must add (and include) a new class (and a new file). It impacts the performance even if you use opcache (opcache aleviates it but it's not magic).
You must define a block of code.

undefined variable $conx in class

I was wondering if you can explain why PHP acts this way when including files in __construct methods.
class sitePosting{
private $conx;
public function __construct() {
include_once("".$_SERVER['DOCUMENT_ROOT']."/auth/db_conx.php");
$this->conx = $conx;
}
It seems that if I call another class which has this file included in its __construct, I get an undefined variable error when trying to use $conx in the first class, but from what I understand isn't __construct run when the object is first built?
What's weirder, if I change...
include_once("".$_SERVER['DOCUMENT_ROOT']."/auth/db_conx.php");
TO
include("".$_SERVER['DOCUMENT_ROOT']."/auth/db_conx.php");
This fixes the problem entirely, but I have no idea why
Any insight into why this occurs is appreciated.
Thanks,
Just as the names says: include_once includes the file only once. If You have included it earlier it won't be included again. Also, classes and functions don't see the global scoped variables unlike JavaScript for example. That's why the $conx variable is unreachable from within You sitePosting class.
It would be better if You placed $conx as class argument like this:
public function __construct($conx) {
$this->conx = $conx;
}
It's called Dependency Injection and is definitely a good practice to use. Makes Your code much cleaner and understendable.

Global vs static variables in PHP

I'm creating a basic framework in PHP. I need to pass data for the current page into different functions, allow them to modify and save it, and then pass it back to the page to be displayed. I was originally planning on storing the data in a global variable like $GLOBALS['data'], but I'm starting to think that using a global is a bad idea. So I'm thinking that instead I will put a static variable in the system class, and access it using system::$data. So, my question is, which would be better and why?
This:
$GLOBALS['data'] = array();
$GLOBALS['data']['page_title'] = 'Home';
echo $GLOBALS['data']['page_title'];
Or this:
class system
{
public static $data = array()
}
function data($new_var)
{
system::$data = array_merge(system::$data, $new_var);
}
data(array('page_title' => 'Home'));
echo system::$data['page_title'];
There really is no difference between a global variable and a public static variable. The class variable is namespaced a tiny bit better, but that hardly makes any difference. Both are accessible anywhere at any time and both are global state.
As it happens, I just wrote an exhaustive article on the subject:
How Not To Kill Your Testability Using Statics
So, my question is, which would be better and why?
You already sense that there is some problem putting this all into globals. Although you have developed some thoughts to encapsulate things into a class.
I think that is a good starting point. Let's add some more spice to the cooking to get this more fluent at the beginning:
$data = new ArrayObject(array());
$data['page_title'] = 'Home';
You have created an object now that you can pass along containing your data. Just pass $data to the area's where it's needed. No global or global static variable needed.
You can even make that type more concrete later on by extending from ArrayObject with your own type.
For the record.
Pro of static:
Clarity of the code. For example:
function fn() {
System::data()
}
versus
function fn() {
global $system;
$system->data()
}
Cons of static:
If you are using psr-4 then you must add (and include) a new class (and a new file). It impacts the performance even if you use opcache (opcache aleviates it but it's not magic).
You must define a block of code.

Using -> with a static function

Hi I'm a bit of a newbie to OOP, i just have a quick question: say I have a function in a class declared as
class House
{
public static function hasAlcohol()
{
// Do Something
}
}
I know i can call this as
House::hasAlcohol()
However, i would also like to know if its okay with coding standards and PHP and if it would be error free to call hasAlcohol() from an instance of house (i tried it and got no errors), for example
$house = new House();
$house->hasAlcohol();
As this has caused several problems for me in the past: Yes, it is valid code. Should you do it? No. It gives the impression that the call is non-static and will most likely cause grief for people working on your code later on. There is no reason to make your code ambiguous.
This used to be possible, but the latest versions of PHP will throw an error, if I remember correctly. You should call static functions statically. You can do $house::hasAlcohol() though.
This used to be possible, but the latest versions of PHP will throw an error, if I remember correctly. You should call static functions statically. You can do $house::hasAlcohol() though.
On a side note, should hasAlcohol really be static? From the name it appears it should be an instance method.
A more recommended pattern if you need constant access to a method is to use a static constructor and get an instance (even if it's a "blank" or "empty") instance to that class. So in the example you've shown, it might be better to have a method like this:
class House
{
public function instance()
{
return new House;
}
public function hasAlcohol()
{
// Do Something
}
}
Then if you ever needed to make a call to "hasAlcohol()" where you don't need an instance for any other purpose, you can do a one-off like so:
House::instance()->hasAlcohol();
or you can instantiate it like in your example:
$house = new House;
$house->hasAlcohol();
or, better yet, use your new factory method:
$house = House::instance();
$house->hasAlcohol();

Good Idea or Bad Idea? Using a Static Class Variable to Store a Global

I have a class that I am using all over the place in my code. It contains settings and other core functionality. Here's what I'm doing right now to use the class.
$settings = new Settings();
$settings->loadSettings();
Then, when I need to the code in some random function in another class, I do something like this:
function abc() {
global $settings;
$variable = $settings->a;
}
I'm sick and tired of randomly calling global $settings all over the place to pull in that settings object. I don't want to use the $_GLOBALS array (I don't know why, I just don't want to).
I'm thinking I want to switch to have a static class variable called $settings inside of settings. The code would look like this:
Settings::$settings = new Settings();
Settings::$settings->loadSettings();
Then, whenever I want to use it, I never have to worry about sucking it in via the global operator:
function abc() {
$variable = Settings::$settings->a;
}
Good idea or bad idea?
Well it's probably an improvement on globals, because it solves all the ugly scoping issues that globals cause. Getting rid of the global operator is generally a good thing! What you are doing is not dissimilar to the singleton pattern, though it's considerably simpler. (See the "Singleton" section at http://php.net/manual/en/language.oop5.patterns.php for more information on the pattern.) Your solution is almost certainly fine for your purposes.
On the other hand, there may be better ways of achieving the same thing that decouple your code more. That is to say, each class becomes more capable of being used in another project without significant recoding. One way to do this would be to "inject" the settings object into each class:
class ABC {
private $settings;
public function __construct($settings) {
$this->settings = $settings;
}
public function someMethod() {
$variable = $this->settings->a;
}
}
This would be more work, but may improve the re-usability of your code. You could then, for example, write a different settings class for every project but use the same ABC class.
This process, where you "inject" an object into another object that depends on it, is called dependency injection. There are other, more complex ways of doing this, including complex containers. See http://fabien.potencier.org/article/11/what-is-dependency-injection for an interesting set of tutorials on the subject. They're probably incidental to your current needs, but may help either now or in the future.
It seems you are looking for a Singleton. Basically the idea is to have a class which has a public static method getInstance() which returns an instance of the class itself. The first time you call the method, it stores the instance in a private property, and all later time it returns the stored instance. In this way, whenever you call Settings::getInstance(), you are guaranteed to have a copy of the same object. Then you can store settings in this object.

Categories