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.
Related
I have TestClass and a public method in it.
I am able to call the same method using :: operator like static method and using an object.
What are the advantages or use of static functions in PHP, if we able to call public functions without creating object of the same class?
<?php
class TestClass {
public function testMethod() {
echo 'Method called';
}
}
TestClass::testMethod();
$classObj = new TestClass();
$classObj->testMethod();
?>
In this case, there is no difference.
However, the point of static functions is to say that some functions don't need an instance of the class in order to be executed. It is possible to call functions statically even if they are not marked as static, but it is technically incorrect to do so. If you have error_reporting(E_ALL) set, it will give you a strict standards error.
This is not because the code won't work, but because it might not.
class TestClass {
private $name = 'Rakesh';
public function doSomething() {
echo "Hi there";
}
public function doSomethingElse() {
echo "Hi there " . $this->name;
}
}
You can call the first function statically and it will work fine. But if you call doSomethingElse statically, it won't work, because it tries to access $this, which is only possible if you have an object.
So we apply the static keyword to doSomething to let (a) PHP and (b) the programmer using the class know that it is possible to call it statically. It's a promise that it will work.
The assumption should be that, if it is not marked as static, you shouldn't call it statically.
PHP's strict standards errors are meant to make your code better, even if it already works. The documentation for the E_STRICT constant says:
Enable to have PHP suggest changes to your code which will ensure the best interoperability and forward compatibility of your code.
In low-level terms, a static function in PHP isn't much different than a member function. The only real difference is that $this isn't provided to a static function.
That means the use of the static keyword is mostly of semantic benefit, as it helps you define the architecture and intended behaviour of your classes.
With that said, you shouldn't abuse the semantics. PHP can (optionally) warn you about those kinds of mistakes, and you should always pay attention to such warnings. The language specification is there for a reason, and it's designed to work in certain ways. If you use static (or any other language feature) incorrectly, then it may not always work as you expect. Future PHP updates or configuration changes could break your code unexpectedly.
Declaring class properties or methods as static makes them accessible without needing an instantiation of the class. A property declared as static can not be accessed with an instantiated class object (though a static method can).
For compatibility with PHP 4, if no visibility declaration is used, then the property or method will be treated as if it was declared as public.
Advantages are ...
1>Hash memory will not create ,hence no wastage of Memory (no memory leak problem)
2>
// This makes little sense
Math m = new Math();
int answer = m.sin(45);
// This would make more sense
int answer = Math.sin(45);
It's like a shortchut, one feature more of php. But, to access to their properties you must declare them like constants. For example:
<?php
class Math{
const pi=3.1416;
}
echo Math::pi;
?>
This is somewhat a follow up to a previous question - but I've distilled the question down and have the "works" vs. "doesn't work" cases narrowed down much more precisely.
My Goal:
I have a class MyClass that has an instance variable myFunction. Upon creating a MyClass object (instantiating), the constructor assigns the instance variable myFunction with the result of a call to create_function (where the code and args come from a db call).
Once this object of type MyClass is created (and stored as an instance variable of another class elsewhere) I want to be able to call myFunction (the instance variable anonymous function) from "anywhere" that I have the MyClass object.
Experimental Cases -- below is my highly simplified test code to illustrate what works vs. what doesn't (i.e. when the expected functionality breaks)
class MyClass extends AnotherClass {
public $myFunction;
function __construct() {
$functionCode = 'echo "NyanNyanNyan";';
$this->myFunction();
/*Now the following code works as expected if put in here for testing*/
$anonFunc = $this->myFunction;
$anonFunc(); //This call works just fine (echos to page)!
/*And if i make this call, it works too! */
self::TestCallAnon();
}
public function TestCallAnon() {
$anonFunc2 = $this->myFunction;
$anonFunc2();
}
}
However, if I do the following (in another file, it errors saying undefined function () in... within the Apache error log.
//I'm using Yii framework, and this is getting the user
//objects instance variable 'myClass'.
$object = Yii::app()->user->myClass;
$object->TestCallAnon(); // **FAILS**
or
$func = $object->myFunction;
$func(); // ** ALSO FAILS **
In addition, several variations of calls to call_user_func and call_user_func_array don't work.
If anyone is able to offer any insight or help that would be great :).
Thanks in advance!
You can't pass references to functions around in PHP like you can in for instance JavaScript.
call_user_func has limited functionality. You can use it like so:
class MyClass {
function func() {}
static function func() {}
}
function myfunc() {}
$i = new MyClass();
call_user_func("myfunc", $args);
call_user_func(array($i, "func"), $args);
call_user_func(array(MyClass, "staticFunc"), $args);
I ended up solving this issue via a workaround that ended up being a better choice anyways.
In the end I ended up having a static class that had a method to randomly return one of the possible identifiers, and then another method which accepted that identifier to build the anonymous function upon each class.
Slightly less elegant than I would like but it ends up working well.
Thanks to everyone for your efforts.
Is there a way to forbid a variable from being picked out of global scope?
Something like:
#index.php
$forbidden = 'you should not be able to access me outside this scope'; // maybe invoke a function or namespaces?
require 'stuff.php';
echo new stuff();
#stuff.php
class stuff
{
public function __toString()
{
global $forbidden; // to result in an error or something?
/*
just a random example, but yes, any way
to somehow make a variable not global?
*/
return 'I am forbidden';
}
}
Have no idea if it's possible, but anyways, interested in OOP only fashion.
Reason?
To disallow a specific class from being instantiated into a variable and then taken out from global scope to reuse it's functions. Make class completely "private", kind of like a master class that does all the automation.
Hope I've made myself clear.
The only way I can think of would be to "fake" global scope...
//index.php
function scope() {
require 'actual.php';
}
scope();
and now, putting code in actual.php looks like "normal" code but it actually is inside function scope. Obviously you can't declare functions or classes in actual.php now, but otherwise it behaves the same, with the exception that any variables declared will be in the function's scope instead of global scope.
I really wouldn't do this though. A beating with a stick usually works if someone does something stupid like globals like that ;)
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();
}
Hey php gurus. I'm running into some bizarre class scope problems that clearly have to do with some quirk in php. Can anyone tell me what out-of-the-ordinary situations might give the following error...
Fatal error: Cannot access self:: when no class scope is active in MyClass.php on line 5
Now, obviously if I were to use self:: outside of the class, I'd get errors... but I'm not. Here is a simplified version of the situation...
//file1
class MyClass{
public static function search($args=array()){
$results = MyDbObject::getQueryResults("some query");
$ordered_results = self::stack($results); //Error occurs here
return $ordered_results;
}
public static function stack($args){
//Sort the results
return $ordered_results;
}
}
//file 2
include_once("MyClass.php");
$args = array('search_term'=>"Jimmy Hoffa");
$results = MyClass::search($args);
given this setup how can I get the error above? Here is what I've found so far...
MyClass::search($args) //does not give the error (usually)
call_user_func("MyClass::search"); // this gives the error!
Any other situations?
If I understand correctly, you are looking for Late Static Binding. This feature requires PHP version 5.3 at least.
You're not passing any parameters, but your method is looking for them. Try
call_user_func("MyClass::search", $args);
This works in php 5.3.1, but call_user_func("MyClass::search"); doesn't
Try this:
call_user_func(array('MyClass', 'search'));
See also example #4 on http://php.net/call_user_func
Your code seems fine. If there's something wrong with it, I must be missing the problem. It appears that your call to self:: is totally within the scope of a class! And a static scope, specifically, which is what self:: is for.
From the 3rd Edition of PHP Objects Patterns and Practice (an awesome book):
To access a static method or property from within the same class
(rather than from a child), I would use the self keyword. self is to
classes what the $this pseudo-variable is to objects. So from outside
the StaticExample class, I access the $aNum property using its class
name:
StaticExample::$aNum;
From within the StaticExample class I can use the self keyword:
class StaticExample {`
static public $aNum = 0;
static public function sayHello() {
self::$aNum++;
print "hello (".self::$aNum.")\n";
}
}
So, I am not sure why this code was failing. Perhaps a PHP bug? I came upon this error when actually trying to use self:: outside of the scope of a class-- my error looked like this:
public static function get_names() {
$machine_names = self::get_machine_names();
return array_map(function ($machine_name) {
$service_settings = self::get_settings_by_machine_name($machine_name);
return $service_settings . $machine_name;
},
$machine_names
);
}
So, I get the error because I use self:: within the scope of the closure. To fix the error, I could make that call to self::get_settings_by_machine_name() before the closure, and pass the results to the closure's scope with use.
Not sure what was happening in your code.