I have a few classes that are often run through var_dump or print_r.
Inside these classes I have a few variables that are references to other, rather large objects that only ever has one instance of each and are only used inside the classes (outside the classes have their own reference to these classes) I do not wish these classes printed in the output, so I have declared them as private static which is working fine.
But my IDE (PHPstorm) is flicking up an error-level alert with Member has private access when I access them through self::$ci->...
I am wondering if this is a bug in the IDE, highlighting because it's probably a bug (aka it's static but nothing outside the class can access it, why would you want to to do that?), or because there is actually something syntactically wrong with it?
As an example here is part of the class,
Note that =& get_instance(); returns a reference to the Code Igniter super object
private static $ci = null;
public function __construct(){
self::$ci = self::$ci =& get_instance();
}
public function product() {
if ($this->product == null) {
self::$ci->products->around($this->relative_date);
$this->product = self::$ci->products->get($this->product_id);
}
return $this->product;
}
In your product() method you're trying to access the private member self::$ci. Your IDE thinks that this method can be accessed anywhere, and detects a conflict with the private static member $ci.
Related
I am learning php and there are still alot of unclear areas for me in the language. I wonder when and why would we use private static properties inside the class. From what I understood private properties may only be accessed by the class where it was defined. So, the private part is clear, but the static is still unclear. In the docs it says:
Declaring class properties or methods as static makes them accessible
without needing an instantiation of the class. A property declared as
static cannot be accessed with an instantiated class object (though a
static method can).
Does that mean that I can access static properties without instantiation of the class. So, for example:
class Foo{
static $bar;
public function __construct($bar){
$this->bar = $bar;
}
So, I can access the $bar property of the class like so?
Foo::$bar
But, if I do this, it wouldn't work?
$foo = new Foo();
$foo::$bar
And, then if do make a property private static for which reason would we do that, since I thought we make them static in order to access them outside of their class and making them private would make that impossible. I would be very grateful if someone could clear this up to me.
When you declare a normal property, there is a different value of that property for every instance you create of that class (each object you create with new Foo). For a static property, there is one copy of that variable for the whole class.
This is separate from the visibility of that variable - a public static property exists once per class, and can be accessed from everywhere; a private static property exists once per class, but can only be accessed from inside that class's definition.
As a simple example, you could have a counter that gave each instance of the class a unique number. You don't need code outside the class to see or change this counter, so you mark it private, but it needs to be shared amongst all instances, so you mark it static.
class Foo {
// Static counter; shared with every instance
private static $nextID=0;
// Normal instance property: each instance will have its own value
private $myID;
public function __construct() {
// Set the ID for this instance to the next ID
$this->myID = self::$nextID;
// Increment the shared counter
self::$nextID++;
}
}
Static context within a PHP class (but outside of a function) is context which exists statically, that is without the need for a backing instance of an object.
Example:
class A {
public $a = 1;
public static $b = 2;
public function instanceFunction() {
A::$a; //Wrong way
$this->a //Right way
A::$b; //Works
self::$b; // Also works
static::$b; // Also also works
}
public static function staticFunction() {
A::$a; //Does not work
$this->a //Error $this within static context
A::$b; //Works
self::$b; // Also works
static::$b; // Also also works
}
}
A::$a; // Error $a is not static so it needs an instance of an object
A::$b; // Works
$Aobject=new A();
$Aobject->a; //Works
$Aobject->b // Does not work
Using self means "refer to the class I've written this in" e.g. in this case it's always A. Using static means "refer to the class I've called this from" which applies if static inheritance is involved which PHP does manage to pull off.
I just started learning OOPS in php. I wrote a simple program for implementing inheritance. I am getting a fatal error of $this when not in object context. Can anyone explain me this error, what does it mean?
here is my code:
<?php
class human{
public $gender;
public function _construct($gender)
{
$this->gender=$gender;
echo $this->get_gender();
}
public function get_gender()
{
return $this->gender;
}
}
class person extends human{
public $name;
public $surname;
public static function set_name($name)
{
$this->name=$name;
}
public static function set_surname($surname)
{
$this->surname=$surname;
}
public static function get_name()
{
return $this->name;
}
public static function get_surname()
{
return $this->surname;
}
}
$john = new person('male');
$john->set_name('John');
$john->set_surname('Williams');
echo $john->get_name().' '.$john->get_surname().'is a '.$john->get_gender();
?>
There are two problems here:
You have defined your methods as static. You should not do that as they are not, they depend on being called on an object as you want to use the objects non-static properties.
You have a typo in your constructor function. The correct name for the constructor is __construct, notice the two _ at the beginning.
In a static function, $this does not exist. You can refer to the class itself with self::. So, instead of $this->surname, use self::surname. As noted below, this will change your error to a new error as it requires the variables to be declared static as well.
Of course, you really need to figure out WHY you made those functions static. Should they be static?
You're trying to access the $this property from a static method. You cannot do this, as anything static can be accessed without instantiating the class, therefore the $this variable would not make sense, as you are not in an actual class instance.
The this keyword refers to the current object you are working with, e.g. if you were to make 5 instances of person, each $this would refer to that specific instance of person, and you could change each objects properties freely.
When you use static you are not referring to any instance, you are simply accessing static variables and calling static methods of that class. All these variables and methods are 'class wide'. That means if you change the static property in one instance of the class, the static property will change in all the classes.
Another way to imagine this is, take when calling the new keyword, you create a new instance of the object. Every instance will have its own copy of all the properties and methods you describe in the class, EXCEPT for the static ones. Imagine that when you access a static method or a static property you are accessing one object always.
That's why it would not make sense to access $this from a static context. You are not referring to any specific instance, only the class itself.
I hope I've explained this well enough, it's a very important concept to grasp in OOP, and it does give some people a lot of trouble to understand the concept.
Why does my function return null?
class TestClass2
{
private $test_var="value";
public function getVar(){
global $test_var;
return $test_var;
}
}
$myclass = new TestClass2();
var_dump($myclass::getVar());
Is there an other way to access variables, which are outside the function, other than passing it in as a parameter, or declaring it as global?
You do not need "global", you just need "$this->test_var" to access your private variable inside a method of your class (in your case, the "getVar" method).
As for calling the function, since it is not static, use "->".
class TestClass2
{
private $test_var="value";
public function getVar(){
return $this->test_var;
}
}
$myclass = new TestClass2();
var_dump($myclass->getVar());
Now that I'm pretty certain what you're asking, I'll go ahead and give you a full answer.
When you call a method, an invisible argument, called $this is passed to it. It is a pointer to your class. I'm not certain this is how it works in PHP, but it's how C++ does it so the behaviors should be similar.
So if you're inside a class's method and you want to access one of its properties, you could tell PHP to use the global scope to break outside of your method and into the class, but that's bulky, obnoxious, and can lead to some complications as your class gets more complex.
The solution is to use the reference to our class that PHP magically gives us. If you want to access $foo->bar inside $foo->getBar(), you can get $this->bar. A good way to think of it is that this is a variable that holds the name of your class.
An additional advantage of this is that, because we're in our class, private properties are visible. This means that $this->bar is valid, whereas $foo->bar isn't, assuming bar is private, of course.
So if we apply this to your code, it becomes a lot simpler and prettier to look at (by PHP standards):
class TestClass2
{
private $test_var="value";
public function getVar(){
return $this->test_var;
}
}
$myclass = new TestClass2();
$myclass->test_var; // Error
$myclass->getVar(); // Not an error
I'm thinking about putting every class into a separate file and doing the static initialization outside of the class definition.
The problem with this is the fact that the initialization will happen before the said class is actually needed (it will happen when the file which contains the class is included for the first time). It's a problem, because it may happen that the class won't be used at all, hence the initialization is unnecessary. And I think the practice of including the used files not in the beginning of your code is simply a dirty technique.
If anybody has a viable solution to this problem, I would greatly appreciate it.
Take a look at code like this. It uses a singleton instance of the database yet you can still create instances of the class:
class DB
{
private static $_db;
public static function pdo()
{
if (is_null(self::$_db))
{
self::$_db=new PDO('pgsql:host=localhost;
port=5432;
dbname=testdb;
user=postgres;
password=abc123');
self::$_db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
return self::$_db;
}
public static function factory()
{
return new self;
}
private function __construct() {}
When you want an instance of the DB, you do DB::factory(). DB uses self::pdo() to return the singleton to access the database.
The singleton answer has a problem here... if you use the static methods before an instance of the class is created... then the static initializer has not run... so you might say that one can run the initializer in every static method... that is true but what about just getting and setting static variables... I suppose one could also use __get and __set magic functions for this... there is just a problem with the language in that it does not support static intialization... here is the way it can be done...
in file Hi.php:
class Hi{
public static $v = "0";
}
Hi::$v= "2";
// end of Hi.php file
simple use a .php file per class... and do the static initialization outside of the
class definition...
You might look up for __autoload when a class is not found it is called and supposed to include the file contains that class. You can put static initializers in that function.
Use singleton pattern instead of static calls:
<?php
class Foo {
protected static $_instance;
/**
* #return Foo
*/
public static function getInstance() {
return (null === self::$_instance)?
self::$_instance :
self::$_instance = new Foo();
}
protected function __construct() {
// initialize here
}
}
This is the way I do this. The only cost is testing the $doneinit static member each time you construct.
class Foo {
private static $doneinit=false;
private static init() {
// do static initialisation here
self::$doneinit=true;
}
public function __construct() {
if (!self::$doneinit) self::init();
// go on to do the rest of construction
}
}
Simple, and it keeps everything within the class.
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);