why does this not work ?
class Test{
private $vars = array('ALL' => 0,
'ONE' => 1);
private $var = $vars['ALL']; // this does not work
function __construct(){
$this->var = $vars['ALL']; // this does work
}
}
code example here: http://codepad.org/QSjHMDij
why is the array not accessible in the statement
private $var = $vars['ALL']; // this does not work
Probably because you can't access $this during the initialization of the class prior to the constructor getting called (which is implied when you tried to do it in the definition for $var.) Some languages (like C#) will let you do it, but I think PHP is one that will not.
Neither "works" in the way you intend. You are not allowed to use variables when declaring instance members (hence the unexpected T_VARIABLE error). In the constructor you are referencing a local variable named $vars which does not exist, meaning you're setting $this->var to NULL.
Access the instance member by doing $this->vars. You can only do this in the constructor.
When declaring members (variables), you can't assign array key values of other members, it causes a parse error.
For example, you're thinking (wrong) that $vars['ALL'] is referring to your private $var - which it is not - it also causes a parse error. There's no way for PHP to know that when you say:
private $var = $vars['ALL'];
that you're actually saying "I want value of $this->vars['ALL'] to be assigned to $this->var", at least not the way you wrote it. That's why you do that from within a function, where you can easily manipulate members, such as you did from the constructor.
You should declare members, their visibility and set some default values (like you did for $var), but you shouldn't point them to other members' values, it's simply - wrong and luckily - it doesn't work :)
You're trying to assign a value to a variable which is designed to be part of an object, rather than the class. What you want is static variables.
Related
I have a very simple issue where I am trying to set a private static property value made up of a constant appended with some text like this:
private static $cssDirectory = APP_ROOT.'css/';
I am getting a syntax error. I can fix this by making the private variable not static and assign a value with a constructor for example but since I want it static I am curious what can I do about it. I can also make a constant for the whole value and use that but again I am curious why I can't do it like I tried. Maybe I am doing something wrong also. Thanks.
From the PHP docs
Class member variables are called "properties"... They are defined by using one of the keywords public, protected, or private, followed by a normal variable declaration. This declaration may include an initialization, but this initialization must be a constant value --that is, it must be able to be evaluated at compile time and must not depend on run-time information in order to be evaluated.
Concatenation is a run-time operation.
You don't need to instantiate and set the property value in the constructor.... you can write a static setter method instead
Note also that PHP 5.6 does allow this type of initialization of class properties
EDIT
Example of a static setter method:
private static $cssDirectory;
public static setCssDirectory() {
self::$cssDirectory = APP_ROOT.'css/';
}
And then you just call
myClassName::setCssDirectory();
before anything else
Inside a class I have 2 associative arrays. I am trying to call elements from one array to be used in another (kind of master) array.
I would like to ask whether the following can be done, or can't, or what I'm doing so wrong;
Please note, the arrays are examples.
class ProductData {
private $texture = [0=>'Cream', 1=>'Powder', 2=>'Liquid', 3=>'Paste', 4=>'Solid'];
private $food = ['type'=>'Pasta', 'info'=>[1=>'750gm', 2=>'$4.50', 3=>$this->texture[4]],
'type'=>'Soup', 'info'=>[1=>'500ml', 2=>'$7.60', 3=>$this->texture[2]]];
// Constructor, Function(s) to access the $food array...
}
Well I have found out the hard way that this cannot be done. I receive a syntax error;
syntax error unexpected '$this' (T_VARIABLE).
If I replace the $this with $texture, I receive the same error;
syntax error unexpected '$texture' (T_VARIABLE).
I'm thinking that this cannot be done, or I'm doing something very wrong, or both.
If this can be done, any assistance is very much appreciated.
Thanks,
njc
class ProductData {
private $texture;
private $food;
function __construct(){
$this->texture = [0=>'Cream', 1=>'Powder', 2=>'Liquid', 3=>'Paste', 4=>'Solid'];
$this->food = ['type'=>'Pasta', 'info'=>[1=>'750gm', 2=>'$4.50', 3=>$this->texture[4]],
'type'=>'Soup', 'info'=>[1=>'500ml', 2=>'$7.60', 3=>$this->texture[2]]];
//other construct stuff
}
}
You can only use constant values to define property values outside class methods. So in your case, you cannot use the $this variable, as it references the current object instance.
You should move the initialisation to the __construct (which is really what is meant to be for)
Check out the documentation:
This declaration may include an initialization, but this initialization must be a constant value--that is, it must be able to be evaluated at compile time and must not depend on run-time information in order to be evaluated.
I am defining a class which has a DateTime object as one of the properties. I want to set its default value to unix timestamp of '-1'. I also want this default value to be constant so that all objects know its value.
But I do not want to declare something like const PROPERTY_DEFAULT_DATE = '-1'; as the property will be a DateTime object and operations/functions using this default value and the property will be difficult to handle if PROPERTY_DEFAULT_DATE is not a proper DateTime object
So, can I have particular object instance of a class as constant inside another class?
The PHP manual says
The value must be a constant expression, not (for example) a variable,
a property, a result of a mathematical operation, or a function call.
Doesn't mention about this, but I think it can't be done (tried lot of variations, always got syntax errors)
If it's not possible, what alternatives do I have?
Edit : I think I need to find the solution to the problem of defining a "Default Value" to my property, which in this case happens to be a DateTime object.
What default value will you set in the __construct()? (no, not NULL please, I expect something more elegant solution must exist) Also keep in mind that it may be used in operations/functions inside the class/subclass
Update : I followed the advice here and created a private $_DEFAULT_DATE property and a getter for it. There is no setter for this property, so I can be assured that it'll not be changed. (Of course, I take care not to change it within class implementation)
Well, unfortunately, the manual is right. You cannot put an object in a constant. You can make it a property, or in your case a static function might be suited;
YourClass::getDefaultDate(); // return DateTime('-1');
It's not possible. The simplest alternative is to use a static property, but it sounds like you want to make sure this property does not change.
So in that case the only logical way to do this, is by making the static property private, and add a static function that returns the DateTime object.
However, I still don't think you want to use a singular object. If any other method requests this default object they'll be able to modify it and you might get weird results. Any request to this method (in my mind) should receive a new or cloned DateTime object.
The manual is correct: no, you can't use objects in const expressions in PHP.
You have to initialize a proper member inside a constructor if you want to use it this way. If you want it to be unalterable, with certain effort you can make it so.
from php.net
about sonstant syntax and use
Someone spoke about "dynamic" assignments to constants. What? There are no dynamic assignments to constants, runtime assignments work only with variables. Let's take the proposed example:
<?php
/**
* Constants that deal only with the database
*/
class DbConstant extends aClassConstant {
protected $host = 'localhost';
protected $user = 'user';
protected $password = 'pass';
protected $database = 'db';
protected $time;
function __construct() {
$this->time = time() + 1; // dynamic assignment
}
}
?>
Those aren't constants, those are properties of the class. Something like "this->time = time()" would even totally defy the purpose of a constant. Constants are supposed to be just that, constant values, on every execution. They are not supposed to change every time a script runs or a class is instantiated.
Conclusion: Don't try to reinvent constants as variables. If constants don't work, just use variables. Then you don't need to reinvent methods to achieve things for what is already there.
From self: you can use private static methods and use magic methods __getStatic (since it's avaliablr only from php 5.3) or use simple __get and property_exist or use Reflection. But actually I don't see the problem which need this solution. Sorry ((
What I think I know so far:
so $this-> is to access a function/var outside its own function/var ?
but how does $this-> know if its a function or a variable ?
why we refer to a var like this $this->data instead of this $this->$data ?
$this refers to the current object that a method has been invoked on. It knows if it's a function if there is a pair of parentheses at the end. We use the former syntax because $this->$data means look at the field whose name is $data; e.g. $this->foo if $data == 'foo'
$this is the variable referring to the object that you are currently inside. $this-> will access either a method or field in the current object.
As for why is it $this->data and not $this->$data, that's just a syntax quirk. You'd have to ask the PHP language designers. It's probably because the latter wouldn't make much sense for a method.
If this looks like Greek to you, then you may want to head over to the PHP manual's section on classes and objects and read up.
$this represents the instance of a given object, from the context of within the object.
I would say, knowing whether you're accessing a method or property is your responsibility. Read documentation. If you're calling an object method using this, it uses the expected syntax of $this->method($args); and properties (member variables) use the expected syntax of $this->var = 'value';
It's a pretty long subject, but in sort, $this is a pointer to an instance. $this->data refers to the data variable of a particular instance(this instance). It is $this->data and not $this->$data just because of convention.
Why does PHP require you to explicitly write $this? I would understand if you had to use $this here:
function foo($bar) {
$this->bar = $bar;
}
But you must write it explicitly in verbose code that looks like this:
$this->var3 = globalFun($this->var, $this->var2[$this->anotherVar], $this->method());
as opposed to:
$var3 = globaFun($var, $var2[$anotherVar], method());
So what is the point of $this?
Additional Bonus Question:
Why do we have to differentiate static references and instances? Why do we need:
static function getValue() {
return self::value;
}
Can't PHP find out at runtime if the variable/method in question is static? Now if I want to change a method from static to non-static, I have to replace all those self:: with $this-> (and vice-versa).
Wouldn't it be better if we had a $this that behaves like it does in Java?
Since this was re-opened, I'll post here my answer, as promised.
TL;DR version If it were not required to qualify a member access, there would be not only performance penalties, but the same line of code could simultaneously signify a field access and a local variable access, depending on the code path.
Full version
In PHP, there's always one symbol table active at the table. This is either the global symbol table or a function/method local symbol table (which by the way, are lazily built). Superglobals and optimizations like compiled variables aside, when a variable $var is requested, it is looked up in the current symbol table. Since the object properties live not on the symbol tables, but instead on either in the objects (the instance properties) or the structure associated the class (the static properties), a lookup for $var can never return a property.
To bring a given variable to the function scope, you must explicitly signal your intention by creating a reference. Examples:
$myglobal = 7;
class A {
private $prop;
public function meth() {
global $myglobal; //bring a global to the current scope
$prop =& $this->prop; //brings a property to the current scope
$local = 4;
$lambda = function () use (&$local) { };
}
}
Obviously, this is just a more sophisticated way to phrase what currently happens. The question is why this behavior?
After all, in Java we only have to type this.prop when there's a local variable called prop hiding the property. Why is this not a good option for PHP?
I can think of several reasons.
The object properties are determined at runtime
PHP has something called "dynamic properties". You can assign new properties to objects at runtime. In fact given two objects of the same class, one can have a given property $a and while the other doesn't. Example:
$obj1 = new stdClass();
$obj2 = new stdClass();
$obj1->a = 7;
In PHP, the defined local variables are determined at runtime
Variables do not have to be declared; consequently, depending on the code path, at some point a variable may or may not be defined. To add insult to the injury, we also have the monster called "variable variables". Example:
class A {
private $g = 3;
public function func($varname) {
if (rand(1,2) == 1) {
$g = 4; //no block scope; the scope is the function's
}
$$varname = 5; //god knows what's happening here
//if local variables hid properties, we'd have trouble
}
}
In Java, a given identifier may also represent, inside the same function, a local variable and a property, but:
Not within the same block (in PHP, all blocks in a function share exactly the same scope).
You get a warning if you're hiding a property.
Crucially, in any given occurrence of an identifier, it's either a property or a local variable, it can't sometimes be one and other times the other.
Consequences
Owing to these facts, it would be impossible to determine at compile time if $var referred to a local variable or to a property. Consequently:
At runtime, every time a variable occurred, it would have to looked up first in the local symbol table, then in the instance properties table, and finally in the static properties list, or any other order (since there can't be an instance and a static property with the same name and static properties need to be declared, there would be some optimization potential here, but the point stands). This means a symbol would have, in the worst case, would have to be looked up in three different places. This is bad from a performance perspective.
A given symbol occurrence could mean different things on different occasions. This is a recipe for disaster.
Okay, so let's remove the need for writing $this everywhere. Take a look at this situation:
class Foo {
public function setBar($value) {
$bar = $value;
}
}
$foo = new Foo();
$foo->setBar('some value');
Is $bar a local variable or a member of $foo?
There has to be some differentiation. They could have allowed declaration of local variables with the var keyword, but that would not have been backwards-compatible and would have been very confusing to people upgrading from older versions of PHP.
Same thing applies to self::. How does the interpreter know whether the function you wanted to call is global or specific to the class?
PHP was not OOP.
Now it is, but with side effects.
Actually, I know people who use this. in Java even where unnecessary because they feel it creates clearer code ;) I don't have a really definite answer, but I guess that, internally, getting $var would always have to be translated to $this->var. So it's not like someone intentionally made things more complicated by forcing us to do $this->var, but just decided to not implement the $var shortcut. If that helps in any way, I don't know ;)