Consider these classes:
class Test_A {
protected $value;
public function __construct() {
$this->value = null;
}
}
class Test_B {
protected $value = null;
public function __construct() {
}
}
I would like to know which one is considered best practice for initializing object properties and why.
Both are syntactically correct and according to PHP manual, a property can be initialized when declared only if the value is not depending on any calculation (protected $a = a + b;). If it does depend on some calculation or runtime value, it should be initialized within the class constructor.
Ref: http://www.php.net/manual/en/language.oop5.properties.php (see Example #1)
Keeping that in mind, is it a good practice to always initialize properties when declaring unless they actually need to be calculated?
If it does depend on some calculation or runtime value, it should be
initialized within the class constructor.
Actually if it depends on some calculation or runtime value, it must be initialized by the constructor. PHP 5.6 relaxes this restriction so that expressions involving scalar values known at compile time will be legal initializers.
Is it a good practice to always initialize properties when declaring
unless they actually need to be calculated?
Sure, as long as you have a meaningful value for them. If you don't explicitly initialize them on declaration they get implicitly set to null.
Related
I'm new to the OOP paradigm, so there's probably a simple explanation for this question...
Do you always need to declare public object-wide variables in a class? For example:
<?php
class TestClass
{
var $declaredVar;
function __construct()
{
$this->declaredVar = "I am a declared variable.";
$this->undeclaredVar = "I wasn't declared, but I still work.";
}
function display()
{
echo $this->declaredVar . "<br />";
echo $this->undeclaredVar;
echo "<br /><br />";
}
}
$test = new TestClass;
$test->display();
$test->declaredVar = "The declared variable was changed.";
$test->undeclaredVar = "The undeclared variable was changed.";
$test->display();
?>
In this code, even though $declaredVar is the only declared variable, $undeclaredVar is just as accessible and useable--it seems to act as if I had declared it as public.
If undeclared class variables are always accessible like that, what's the point of declaring them all up front?
That variable isn't uninitialized, it's just undeclared.
Declaring variables in a class definition is a point of style for readability.
Plus you can set accessibility (private or public).
Anyway, declaring variables explicitly has nothing to do with OOP, it's programming-language-specific. In Java you can't do that because variables must be declared explicitly.
If you declare a member inside the class you can set its accessibility e.g
private $varname;
You should always declare your member variables and specify their accessibility within your classes. I like to put this information at the end of the class after my functions.
You should define them as soon as you have enough information to do so. Possibly in the constructor or via setter functions.
It is important to do this because it makes life much easier for people working with your code. They don't have to guess where different properties are coming from or why they're there. Also, most (if not all) IDEs will not pick up on class variables unless you've declared them somewhere. Code completion/hints are one of the many benefits of IDEs and without declaring your variables, you will render that functionality useless.
General OOP paradigm of encapsulation says you should not expose your inner state variables out side that means they should be private, that allows you to change an implementation of your class without need to change the code where you make use of it. It's better practice to initialize variables via constructors and getters and setters method of the class.
In general variables should be initialized as soon as you have enough info to do it properly.
If a class variable needs certain info to be sensibly initialized then that info should be passed to the constructor.
Using PHP's syntax to implicitly declare variables at the point of definition is, IMHO a surefire way to introduce bugs - if your class needs a variable then declare it, and use all of the information hiding that OOP affords you.
As Federico Culloca said "That variable isn't uninitialized, it's just undeclared". Also you didn't define any access modifiers for them so that they behaving like public modifier applied to them.
You may already have known, PHP is a loosely typed language. But a programmer should always follow the best practices and define access modifiers manually. It increases code readability.
You can use private modifier for class level variables and provide accessor and mutator methods (Getters and Setters) for them when needed.
TLDR: Only Define What Isn't in The Default/Public
To define or not define global variables within class scope — ultimately, it is a design decision that should be taken to improve code readability, and nothing more. Personally, I don't "define all of these," and I use the default scope of public (Source: PHP.net -> Visibility). I do that until I actually need to change any of them for a particular need.
The Basic Objection
"But shouldn't that be set so we can define public and private as needed?" : If you need to set a global variable's status, then set it. Until you set it, it is public. So, set it when you need it. Don't write code that does nothing with the hope that one day in the future you'll thank yourself -- odds are you may need to completely revamp everything your old self did. And what if you have hundreds of variables all set to the same default instance? How does that help anyone?
Why Avoid Hardcoding the Accessibility Value on Attributes?
At some point, we will be able to configure the default, and then all that code that hard-coded this class accessibility, or that class accessibility, will need to be reprogrammed. In general, hard-coding is bad, and the large amounts of typing/copying-pasting associated with class attribute access definitions is just not worth the result. Use the default.
It's Really All About Style
If all your class variables public and the extra global definitions (100's of them maybe) doesn't help you, then dump them. If they give structure to your code, though, then keep them. It's something done to help the coder, not the compiler.
Which would you rather have to fix?
This?
class basicscript extends baseformat {
public function __construct($args) {
$this->startUp($args);
return $this;
}
}
Or this?
class basicscript extends baseformat {
public $desired_script;
public $desired_action;
public $object_code;
public $object_parent;
public $object_list;
public $script_location;
public $script_name;
public $script_file;
public $script_extension;
public $script_format;
public $script_format_lower;
public $script_args;
public $authentication_object;
public $cleanser_object;
public $query_object;
public $db_access_object;
public $domain_object;
public $language_object;
public $dictionary;
public $time;
public $cookie;
public $formats_object;
public $version_object;
public $redirect_object;
public function __construct($args) {
$this->startUp($args);
return $this;
}
}
This may be a basic question, but it has kept me wondering for quite some time now.
Should I declare all private/local variables being private? Or is this only necessary for "important" variables?
For instance, I have the (temporary) result of a calculation. Should I pre-declare this variable?
Hope someone can point this out.
Since you're talking about private, protected and public I take it you're talking about properties, instead of variables.
In that case: yes, you should declare them beforehand.
Because of how PHP objects are designed, an array (properties_table) is created on compile time. This array ensures that accessing a given property is as fast as possible. However, if you add properties as you go along, PHP needs to keep track of this, too. For that reason, an object has a simple properties table, too.
Whereas the first (properties_table) is an array of pointers, the latter is a simple key => value table.
So what? Well, because the properties_table contains only pointers (which are of a fixed size), they're stored in a simple array, and the pointers are fetched using their respective offsets. The offsets are stored in yet another HashTable, which is the ce->properties_info pointer.
As bwoebi pointed out to me in the comments: getting the offset (HashTable lookup) is a worst-case linear operation (O(n)) and predefined property lookups are constant-time complex operations (O(1)). Dynamic properties, on the other hand need another HashTable lookup, a worst-case linear operation (O(n)). Which means that, accessing a dynamic property takes in average about twice as long. Authors of the Wikipedia can explain Time-Complexity far better than I can, though.
At first, access modifiers might seem irrelevant. As you go along, you'll soon find that sometimes, you just don't want to take the chance that some property of some object gets modified by some bit of code. That's when you see the value of private.
If an object contains another object, that holds all sorts of settings that your code will rely upon, for example, you'll probably use a getter method to access those settings from the outside, but you'll leave that actual property tucked away nicely using private.
If, further down the line, you're going to add data models and a service layer to your project, there's a good change you'll write an (abstract) parent class, if only for type-hinting.
If those service instances contain something like a config property, you'll probably define that getter in the parent class (to only define it once). private means that only the current class has access to a property, but since you're not going to have an instance of the parent to work with, but an instance of the child, you'll see why protected is invaluable when dealing with larger projects, too.
As far as temporary variables are concerned, be it in methods, functions or anywhere else, you don't have to predeclare them, except for, in certain cases arrays:
public function foo()
{
$temp = $this->getSomeValue();
return $temp ? $temp +1 : null;
}
Is perfectly valid, and wouldn't work any better if you were to write
public function foo()
{
$temp;// or $temp = null;
$temp = $this->getSomeValue();
return $temp ? $temp +1 : null;
}
However, it's not uncommon to see simething like this:
public function bar($length = 1)
{
for ($i=0;$i<$length;$i++)
{
$return[] = rand($i+1, $length*10);
}
return $return;
}
This code relies on PHP being kind enough to create an array, and assign it to $return when the $return[] = rand(); statement is reached. PHP will do so, but setting your ini to E_STRICT | E_ALL will reveal that it doesn't do so without complaining about it. When passing 0 to the method, the array won't be created, and PHP will also complain when it reaches the return $return; statement: undeclared variable. Not only is it messy, it's also slowing you down! You're better off declaring $return as an array at the top of the scope:
public function bar($length = 1)
{
$return = array();//that's it
for ($i=0;$i<$length;$i++)
{
$return[] = rand($i+1, $length*10);
}
return $return;
}
To be on the safe side, I'd also check the argument type:
/**
* construct an array with random values
* #param int $length = 1
* #return array
**/
public function bar($length = 1)
{
$length = (int) ((int) $length > 0 ? $length : 1);//make length > 0
$return = array();
for ($i=0;$i<$length;$i++)
{
$return[] = rand($i+1, $length*10);
}
return $return;
}
In most if not all cases: yes.
If the variables are class properties they absolutely should be declared before use.
If the variable is local to a function, declare it in that function before you use it. Function variables are confined to the function's scope (local variables). They don't have to be declared before use but it's good practice to do so, and it gets rid of a warning message if you do. If they are not used anywhere else, they should not be properties though,
If you are using it in the context of the whole class, then yes, you should define your variable as a member of the class.
However, if you are talking about a local variable within the context of a single function and the variable does not need to be used elsewhere (or is not returned), then no.
Essentially you need to determine the importance and scope of your variable before deciding whether to make it a class property or not.
For example:
<?php
class Test {
private $test; // Private property, for use in the class only
public $public_test; // Public Property, for use both internally and external to the class as a whole
public function testing() {
$local = 5; // Local variable, not needed outside of this function ever
$this->test = rand(1, 5);
$calc = $local * $this->test; // Local variable, not needed outside of this function ever
$this->public_test = $calc / 2; // The only thing that the whole class, or public use cares about, is the result of the calculation divided by 2
}
}
It's generally a good rule of thumb for variables to define and initialize them before use. That includes not only definition and initial value but also validation and filtering of input values so that all pre-conditions a chunk of code is based on are established before the concrete processing of the data those variables contain.
Same naturally applies to object members (properties) as those are the variables of the whole object. So they should be defined in the class already (by default their value is NULL in PHP). Dynamic values / filtering can be done in the constructor and/or setter methods.
The rule for visibility is similar to any rule in code: as little as necessary (the easy rule that is so hard to achieve). So keep things local, then private - depending if it's a function variable or an object property.
And perhaps keep in the back of your mind that in PHP you can access private properties from within the same class - not only the same object. This can be useful to know because it allows you to keep things private a little bit longer.
For instance, I have the (temporary) result of a calculation. Should I pre-declare this variable?
This is normally a local variable in a function or method. It's defined when it receives the return value of the calculation method. So there is no need to pre-declare it (per-se).
...
function hasCalculation() {
$temp = $this->calculate();
return (bool) $temp;
}
...
If the calculation is/was expensive it may make sense to store (cache) the value. That works easily when you encapsulate that, for example within an object. In that case you'll use a private property to store that value once calculated.
Take these rule with a grain of salt, they are for general orientation, you can easily modify from that, so this is open to extend, so a good way to keep things flexible.
I was looking through the PHP documentation and saw several comments where a variable was initialized outside of a class's constructor, similar to the following:
classMyClass {
private $count = 0;
public function __construct() {
//Do stuff
}
}
In PHP Objects, Patterns, and Practice, the author recommends using constructs only for the initialization of properties, deferring any heavy lifting or complex logic to specialized methods. This tutorial (a quick example that I found on Google) also recommends using constructors to initialize properties: http://www.killerphp.com/tutorials/object-oriented-php/php-objects-page-3.php.
Why would you want to initialize a variable outside the constructor? Is this just sloppy coding, or is there a reason to do something like this? I have to say that until recently, I initialized default values outside the constructor, and there doesn't seem to be any programmatic advantage of one way over the other.
When you initialize a variable outside of the constructor, it must be initialized as a constant. You can't do any operation to initialize it. Thus, the initial value of that member is actually a part of the class signature.
For example, this is invalid:
private $var = $othervar;
private $var = func();
You could do it in the constructor as well, but it would be a bit more verbose and add some clutter to the constructor unless there was some sort of logic going on.
More a comment than an answer, but please elaborate here a little:
Since it is recommended to use constructors for property initialization only,
Who says this and why? I assume the only relates to something else than property definitions with default values.
An answer part:
By default in PHP variables do not need to be defined because variables are then defined when first accessed in a write context. All variables, including undefined ones contain NULL (Demo):
class A {}
$a = new A;
var_dump($a->property); # NULL
Introducing class variables (properties) PHP then allowed to actually define variables. Those still return NULL by default, but they are defined (Demo):
class A {
public $property;
}
$a = new A;
var_dump($a->property); # NULL
In the next step of the evolution, this language construct also allows to specify a constant expression. That is constant because definition is compile-time (not run-time as the when the constructor is invoked). An example (Demo):
class A {
public $property = 'hello';
}
$a = new A;
var_dump($a->property); # string(5) "hello"
As this is compile- but your constructor run-time, I find it hard to compare both feature with another. Also it's not clear why you say that initializing via the constructor is recommended.
Far from sloppy... it's good programming practice. As you would also do in Java/C++, it just sets them up, and then you can do any initialisation in the constructor - usually to sent them to non-defaults as such.
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 ((
I would like to define a class constant using a concatenation of an existing constant and a string. I can't predefine it because only scalars are allowed for predefining constants, so I currently have it as part of my constructor with a defined() function checking if it is already defined. This solution works but my constant is now unnecessarily global.
Is there a way to define a class constant at runtime in php?
Thank you.
See the PHP manual on Class constants
The value must be a constant expression, not (for example) a variable, a property, a result of a mathematical operation, or a function call.
In other words, it is not possible. You could do it with runkit_constant_add but this sort of monkey patching is strongly discouraged.
Another option is to use the magic methods __get() and __set() to reject changes to certain variables. This is not so much a constant as a read-only variable (from the perspective of other classes). Something like this:
// Completely untested, just an idea
// inspired in part from the Zend_Config class in Zend Framework
class Foobar {
private $myconstant;
public function __construct($val) {
$this->myconstant = $val;
}
public function __get($name) {
// this will expose any private variables
// you may want to only allow certain ones to be exposed
return $this->$name;
}
public function __set($name) {
throw new Excpetion("Can't set read-only property");
}
}
You cannot do exactly what you want to do, per Gordon's answer. However, you can do something like this. You can only set it once:
class MyClass
{
private static $myFakeConst;
public getMyFakeConst()
{
return self::$myFakeConst;
}
public setMyFakeConst($val)
{
if (!is_null(self::$myFakeConst))
throw new Exception('Cannot change the value of myFakeConst.');
self::$myFakeConst = $val;
}
}