Using $this, self::, parent:: for code readability - php

I would like to know if it is acceptable/preferred to use self::method() and parent::method() when working in php classes.
You can use $this->method() but $this-> can also refer to a class variable, a parent class variable, or a method from the parent class. There is no ambiguity in self::
Is self:: depreciated and/or are there any caveats or cons to using this style?
I understand that self:: and parent:: refer to a static instance of the class, but in kohana, unless you specifically define a method as static, there does not seem to be a difference.
Thanks.
Added an example:
Assuming this application stores forums from multiple websites...
class Forum_Controller extends Controller {
function __construct()
{
parent::__construct();
}
function index()
{
echo self::categories();
}
/*
* get a list of categories from a specific site.
*/
private function categories()
{
$db = new Database;
$categories = $db->query("
SELECT * FROM
forum_categories
WHERE fk_site = '$this->site_id'
");
$view = new View('categories_view');
$view->categories = $categories;
return $view;
}
}
This examples works in kohana with error reporting set to:
error_reporting(E_ALL & ~E_STRICT);
$this->site_id is defined in the main Controller_Core class (a library in kohana).
As far as I know, $this is not supposed to be available since I am calling self::categories() in a static manner, but it is only when i define categories() as static that it throws an error.
But as I said I much rather prefer using self:: because from a readability perspective, I know exactly where this function should be, rather than using $this which causes ambiguity, to me that is.

There is a difference.
$this refers to an instance of an object.
parent and self are used to call methods statically.
This page of PHP's manual explains it in better detail than I have time to write at the moment. The first example in particular should help to highlight some of the differences. I encourage you to copy paste the first example and mess about with it, as I think its an important concept to get in your mind if you don't already know the difference.

Controllers are not static in Kohana, although they can contain static member variables / methods or constants.
self:: is a shorthand way of writing ClassName:: i.e
class Animal
{
public static $arms = 0;
}
class Dog extends Animal
{
public static $leg = 0;
const NAME = 'dog';
public static function bark()
{
echo 'Woof';
}
}
To call static functions or get constants from a class we use the scope resolution operator ::. Static functions are per class not per object. Saying :: refers to static instances of a class is wrong, it is just a way to access the static methods - there isn't an object instance that has these methods.
so:
Dog::bark(),
Dog::$leg,
Dog::NAME,
we can also use
Animal::$arms
Inside the class Dog we can use self:: and parent:: so that we do not need to type the full class name (as it could be very long!)
In answer to your question though: No - self:: is not deprecated and no it is not bad practice to use it. The reason it is not used in kohana core is for a very different reason.... (transparent class extensions with eval read below for more info...).
p.s calling non-static methods statically is wrong and shouldn't be allowed- if you set error_reporting(E_ALL | E_STRICT) (like you should during development) you will see an error being raised.
Basically what happens is:
Core has a file called:
class Controller_Core {
public function someMethod(){}
}
You create:
// We can use someMethod of Controller_Core
Index_Controller extends Controller {}
This is really extending Controller_Core UNLESS you have created MY_Controller.php which would be class Controller extends Controller_Core.
//MY_Controller.php
class Controller extends Controller_Core
{
// overloads Controller_Core::someMethod without us having to change the core file
public function someMethod(){}
}

I think self:: is used generally for static functions and properties.
I use Kohana, and perhaps the controllers are made static.

I couldn't add a comment (apparently i do not have the required rep!)
class Forum_Controller extends Controller {
public function __construct()
{
parent::__construct();
}
public function index()
{
echo self::categories();
}
/*
* get a list of categories from a specific site.
*/
private static function categories()
{
$db = new Database;
// You cannot use $this in a static function, because static functions are per class
// and not per object it doesnt know what $this is :) (make private static $site_id and use self::$site_id) if this is what you want
$categories = $db->query("
SELECT * FROM
forum_categories
WHERE fk_site = '$this->site_id'
");
$view = new View('categories_view');
$view->categories = $categories;
return $view;
}
}
Like i said, you should use error_reporting(E_ALL | E_STRICT); (change it in the kohana file )
calling private function categories() statically works due to a bug in PHP, you shouldn't be able to do it :)

I strictly use self:: only for static variables and static member function

another thing to note by the way is that this isn't very good MVC design to be making static controller functions that return lists of categories.
Controllers are for dealing with requests, Models are for dealing with data (which is what this is) and Views are for display.
make a model!
class Category_Model extends Model
{
public function categories($site_id)
{
$categories = $this->db->from('forum_categories')->where('fk_site',$site_id)->get();
return new View('categories_view', array('categories' => $categories));
}
}
...
$cat = new Category_Model;
echo $cat->categories(1);

Related

Calling a static parent method while instantiating child class

I'm changing my class structure around to store common database methods in one class. Then extending it from a child class. This should cut down on code but also allows me to overwrite the parent methods when I need to.
I've done the following, for this example I've simplified to the basics compared to the original code which contains more classes.
class parent_object{
private $table_name;
public function all_records(){
$sql = "SELECT * FROM ".$this->table_name;
return $this->execute_sql($sql);
}
}
class child_object extends parent_object{
protected static $table_name="tbl_name";
public function __construct(){
parent::__construct(self::$table_name);
}
}
I want to call the all_records() statically to save myself creating a new object every time.
I'm stuck having to instantiate the child and then call the parent method
$child = new child_object();
$all = $child->all_records();
What I really want to be able to call the parent method statically:
$all = child_object::all_records();
I understand why I can't do it with my code, but would like some way that the child instantiates first then accesses the parent method.
I could write all_records() method in the child_object to instantiate itself and call the parent all_records() but that sort defeats the purpose of extending to cut down on code and the same methods in my child class.
I'm sure its quite simple or some new high level oop function can do it.
Thanks for your help.
The answer is relatively simple, you can turn all your properties into static properties, and then use static:: instead of self::.
http://php.net/manual/en/language.oop5.late-static-bindings.php
Solving your problem this way is considered a bad practice though. Good luck.
You could do something like this:
class child_object extends parent_object
{
protected static $table_name="tbl_name";
public static function factory()
{
return new child_object();
}
public function __construct()
{
parent::__construct(self::$table_name);
}
}
Then when you use it you just do:
$all = child_object::factory()->all_records();

Php static child classes inheritance

I recently began to develop in php5 in an object oriented way and I'm stuck at something. I would really appreciate your help/recommendations.
Bear with me in this since it ended up in a mess :-(
This is my scenario (hope I can elaborate on this clearly): I have two dynamic classes, Client and Supplier which use methods of a static class called Vocabulary. Vocabulary is a class that pulls vocabulary terms from a source which can be: plain text file, mongodb database or mysql database. An entry in a configuration file determines which of the
aforementioned three types of sources the application will use.
class Client {
public function foo() {
...
Vocabulary::getTerm();
...
}
...
}
class Supplier {
public function bar() {
...
Vocabulary::getTerm();
...
}
...
}
class Vocabulary {
public static function useVocab($vocab) {
$_SESSION['vocab'] = $vocab;
}
public static function getTerm($termKey) {...}
...
}
I planned to create Vocabulary child classes for each of the types I want to support, for example: Vocabulary_file, Vocabulary_mongodb and Vocabulary_mysql.
Vocabulary_file will override its parent useVocab() because it needs to perform additional operations appart from setting the $_SESSION variable, but
Vocabulary_mongodb and Vocabulary_mysql don't need to override their useVocab() parent method (they just need the $_SESSION variable set).
All three Vocabulary "child" classes will override getTerm() method.
The following is what I tried and this is the mess I ended up with :-(
For Vocabulary_mongodb and Vocabulary_mysql, since useVocab() doesn't exist but is inherited from Vocabulary, "method_exists()" returns true and that call
causes an infinite loop.
I looks weird both calling the child explicitly in Vocabulary and calling the parent:: in the child class.
After lots of cups of coffee I have exhausted all my wits and my brain is damaged.
// Class Vocabulary modified to make it call the desired "child" class too
class Vocabulary {
// This would execute "child" class method
private static function _callChild($method, $args) {
$child_class = 'Vocabulary_' . Config::$vocab['type']; // Config::$vocab['type'] can be: file, mongodb or mysql
if (method_exists($child_class, $method)) {
return call_user_func_array($child_class . '::' . $method, $args);
} else {
return false;
}
}
public static function useVocab($vocab) {
$_SESSION['vocab'] = $vocab;
self::_callChild(__FUNCTION__, compact('vocab'));
}
public static function getTerm($termKey) {
$termKey = strtolower($termKey);
self::_callChild(__FUNCTION__, compact('termKey'));
}
...
}
class Vocabulary_file extends Vocabulary {
public static function useVocab($vocab) {
parent::useVocab($vocab);
// some specific stuff here
}
public static function getTerm($termKey) {
parent::getTerm($termKey);
// some specific stuff here
}
}
class Vocabulary_mongodb extends Vocabulary {
public static function getTerm($termKey) {
parent::getTerm($termKey);
// some specific stuff here
}
}
class Vocabulary_mysql extends Vocabulary {
public static function getTerm($termKey) {
parent::getTerm($termKey);
// some specific stuff here
}
}
I would like to know how can I design the Vocabulary classes in order to keep the Vocabulary::... like calls in Client and Supplier and let Vocabulary know which child class use for the type configured in "Config" class.
Any advice will be greatly appreciated.
Cheers
If you're using all static methods, you may as well not use OOP at all, it's basically all just global function calls. If you want inheritance with polymorphism to work, you pretty much need to instantiate your classes. The polymorphism then comes from the fact that the instantiated objects can be anything, but you're calling the same methods on them. E.g.:
abstract class Vocabulary {
abstract public function getTerm($termKey);
}
class Vocabulary_File extends Vocabulary {
public function getTerm($termKey) {
// get from file
}
}
class Vocabulary_MySQL extends Vocabulary {
public function getTerm($termKey) {
// get from database
}
}
You can use this polymorphic like this:
if (mt_rand(0, 1)) {
$vocab = new Vocabulary_File;
} else {
$vocab = new Vocabulary_MySQL;
}
// This call is polymorphic.
// What exactly it does depends on which class was instantiated.
$vocab->getTerm('foo');
This is how polymorphism is really useful. The interface (getTerm($termKey)) is defined and unchanging between classes, but the specific implementation changes. If your code is hardcoding calls to Vocabulary::getTerm(), that's not polymorphism. With your structure you're also violating an important OO design rule: The parent does not know about its children, and it does not interact with its children. The children override functionality of the parent, not the other way around.
You also shouldn't use the $_SESSION as a form of global storage. Keep objects self contained.
The keyword self suffers from inability to handle 'late-static-binding'. Basically, in the parent class, self thinks it's the parent class when it's inside it's own static functions (since self is still evaluated at compile time for legacy reasons).
You need to use static instead of self in the parent class (assuming you have php 5.3 or higher).
BTW: the parent keyword functions as you'd expect as the parent has to be known at compile time anyhow.
Here's an example:
public static function getTerm($termKey) {
$termKey = strtolower($termKey);
static::_callChild(__FUNCTION__, compact('termKey'));
}
If you're using php 5.2 and earlier, you have to try a hack around, like require all child classes to have static functions that return their class name. I hope you're on php 5.3 or higher...

Is passing $this to a static method tight coupling?

Here is a simple example:
class Class_A {
protected $_property;
public function method()
{
Class_B::method($this);
}
public function getProperty()
{
return $this->_property;
}
}
class Class_B {
public static function method(Class_A $classA)
{
$classA->getProperty();
}
}
$classA = new ClassA();
$classA->method();
Is it ever okay to pass $this as a parameter to the method of another class? Or is that always going to be tight coupling? I could pose another similar example using a Factory Pattern in place of the static method call.
It depends on the exact behaviour of Class_A and Class_B, but in general it would probably be better to define an interface which is implemented by Class_A and type hint for that. The methods of Class_A that are required by Class_B (e.g. getProperty()) should appear in your interface. Then, if you want to switch Class_A with another class at a later date, all it has to do is implement the same interface.
Yet again, it depends on the behavior of the classes in question, but if there was another Class_C for example that also used Class_B 's static method you might want to consider having Class_A and Class_C extend Class_B. More information can be found on the php object inheritance page.

$this->class->function(): how does it work?

I've been programming in PHP for several years and I've only just recently begun to look at object oriented code. Now I understand classes and such:
class Myclass {
public function __construct() {
}
}
and all that good stuff... I also understand creating functions and calling in my index.php:
$someVar = new Myclass;
One thing I've been trying to understand, being that i've recently looked at codeigniter and I like one thing about it and want to try and accomplish the same thing without actually using codeigniter.
in code igniter they have the variable $this appear to be their class variable. But by using that, you're able to call from multiple classes all at once.. such as:
$this->load->module(); which is in one class file..
$this->db->query(); which is in another class file.
I've searched google for the last few days trying to figure out how to do this same thing where each class would have the correlation between them all allowing me to run $this->class_name->function_name in my projects instead of creating a new variable for each class or for the sake of a clean index file, having every function in a single class file.
Any information (aside from buy this book - as that isn't an option for me) is greatly appreciated and I will thank you now (and will probably thank you again later just for good measure).
I've been reading you and Phil's comments. First off, you can't use $this on index.php. $this can only be used in the context of an object. So you could do,
$someVar = new Myclass;
...
$someVar->db->something();
...instead.
I'm not entirely sure what you mean by "read classes," but you can assign members to MyClass exactly as Phil indicates:
class MyClass {
private $inj;
function __construct(Injected $inj) {
$this->injected = $inj;
}
}
Note that the private $inj declaration is not mandatory, but skipping it is dangerous. Any non-declared members added are automatically public, and this can potentially screw with you if you rely on magical get. I would declare the properties you need.
Finally, you either need to include all class definitions you will use, use a function like load_class(), or use autoloading. If Injected above is not a declared class, you will get an error when trying to create one. load_class() almost certainly includes the class definition somehow.
The load and db references are class properties which are themselves other objects with public module() and query() methods respectively. For example
class MyClass
{
/**
* #var CI_DB
*/
private $db;
/**
* #var Loader
*/
private $load;
public function __construct(CI_DB $db, Loader $load)
{
$this->db = $db;
$this->load = $load;
// PHP also allows you to add arbitrary object properties
// that receive a "public" visibility
// Please note, this is not a good practice
$this->foo = new Foo;
}
public function someMethod()
{
$this->load->module();
$this->db->query();
// You can also use foo even though it is not defined
// in the class properties
$this->foo->something();
}
}
See http://www.php.net/manual/en/language.oop5.properties.php
Adding the foo property like we did is dangerous. Because it receives the public visibility, it may be altered externally to the class.
$class = new MyClass($db, $load);
$class->foo = new Bar;
$class->someMethod(); // will break if Bar does not contain a something() method

PHP static variables in an abstract parent class

Quick code with the question included:
abstract class ClassParent {
public static $var1 = "ClassParent";
}
class ClassChild1 extends ClassParent{
public static function setvar1(){
ClassChild1::$var1 = "ClassChild1";
}
}
class ClassChild2 extends ClassParent{
public static function setvar1(){
ClassChild2::$var1 = "ClassChild2";
}
}
ClassChild1::setvar1();
echo ClassChild2::$var1;
// Returns "ClassChild1". Shouldn't this still be "ClassParent"?
I am assuming that the above is expected behaviour and not a PHP bug. In that case, how could I declare a static variable in the parent class which will be handled separately for the child classes. In other words, I want to have separate static values PER CHILD CLASS. Must I declare the static variable specifically in the child classes or is there perhaps another way?
Thanks!
EDIT: On further investigation, I think what you're asking is not directly possible, even with late static binding. Actually, I am a little surprised.
The answer to this question provides some workarounds.
Original answer:
In a parent class, if you refer to a static variable in the form:
self::$var
It will use that same variable in all inherited classes (so all child classes will be still accessing the variable in the parent class).
This is because the binding for the self keyword is done at compile-time, not run-time.
As of PHP 5.3, PHP supports late static binding, using the static keyword. So, in your classes, refer to the variable with:
static::$var
And 'static' will be resolved to the child class at run-time, so there will be a separate static variable for each child class.
Thanks for this question! I had some problems I couldn't track and this has helped me solve them. :)
You might be interested to know that there is a bug report for this behavior which includes the workaround. In your case this would be:
class ClassChild1 extends ClassParent{
public static function setvar1(){
$tmp = 'x';
static::$var1 =& $tmp; // break reference
// and now this works as expected: (changes only ClassChild1::$var1)
static::$var1 = "ClassChild1";
}
}
// do the same in ClassChild2...
Ugly as hell, I agree - but PHP works as expected this way, plus it has no side effects.
This is indeed a very doubtful (and poorly documented) "feature" in my eyes - let's hope they change it someday.
Ugly solution, but it works.
I've moved static $var1 to a trait that is required to be used in child classes.
It is essentially the same as declaring $var1 in each child class.
However, using this method there is no chance you forget to declare $var1.
trait Var1Trait
{
public static $var1 = "ClassParent";
protected function requiresVar1Trait()
{
}
}
abstract class ClassParent
{
abstract protected function requiresVar1Trait(); // make sure that Var1Trait is used in child classes
}
class ClassChild1 extends ClassParent
{
use Var1Trait;
public static function setvar1()
{
ClassChild1::$var1 = "ClassChild1";
}
}
class ClassChild2 extends ClassParent
{
use Var1Trait;
public static function setvar1()
{
ClassChild2::$var1 = "ClassChild2";
}
}
ClassChild1::setvar1();
echo ClassChild2::$var1;
// Returns "ClassParent" as requested

Categories