I noticed two ways in PHP to do the same thing. Can you tell me which way is a better programming practice?
In the first example, I use a private variable on the class. On the second example, I use a static variable in a class method.
class Test {
private $_myvar;
public function getVar(){
if (!isset($this->_myvar)) {
$this->_myvar = "test\n";
}
return $this->_myvar;
}
}
$oTest = new Test();
echo $oTest->getVar(); // sets var first time and returns it
echo $oTest->getvar(); // pulls from cache
Or:
class Test {
public function getVar(){
static $myvar;
if (!isset($myvar)) {
$myvar = "test\n";
}
return $myvar;
}
}
$oTest = new Test();
echo $oTest->getVar(); // sets var first time and returns it
echo $oTest->getvar(); // pulls from cache
That is like saying which room is better the Kitchen or the Bathroom, they are both rooms, but they have different functions.
A static variable is the same in multiple objects.
An instance variable, declared via private above is particular to a given object.
Note that private is an access modifier, static is not, a variable can be both.
In the location you have your static variable, within the function, it is not a class/object variable at all, but a traditional function-level static variable, which will be single-instanced across all calls to the function, making it similar to a class-level static variable, but only accessible within the method it is defined within.
With the class property (be it public, private or protected), the variable is accessible to other parts of the class.
With the static variable, it is only visible to that method of the class.
I would suggest using the class property (but probably not private, which I generally don't find much use for; protected is normally a better idea) as it's easier for testing later; you can't do anything to unset, alter or check the static variable.
I see some possible confusion in the other answers here between static variables and static class properties. PHP uses the same modifier, but the behaviour is quite different; an example follows.
<?php
class Foo {
// Static class property
public static $bar = 'bar';
public function blarg() {
static $bar;
if (empty($bar)) {
$bar = 'blarg';
}
return $bar;
}
}
In the above example the static class property can be accessed using Foo::$bar (or self::$bar within the class and static::$bar in PHP 5.3); the static variable cannot and is only visible inside the function blarg().
Neither is "better". It would be like asking whether a screwdriver is better than a tenon saw.
The private variable in your first example will only be available to that instance of the class (although only to its methods). Create a new instance, and the variable can and will have a different value.
The static variable in your second example will be available to all instances of that class, admittedly only in that method. But set it one instance, and a second instance will see the same value.
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've been looking at some code and am having a hard time working out variable declaration in php classes. Specifically it appears that the code i'm looking at doesn't declare the class variables before it uses them. Now this may be expected but I can't find any info that states that it is possible. So would you expect this:
class Example
{
public function __construct()
{
$this->data = array();
$this->var = 'something';
}
}
to work? and does this create these variables on the class instance to be used hereafter?
This works the same as a normal variable declaration would work:
$foo = 'bar'; // Created a new variable
class Foo {
function __construct() {
$this->foo = 'bar'; // Created a new variable
}
}
PHP classes are not quite the same as in other languages, where member variables need to be specified as part of the class declaration. PHP class members can be created at any time.
Having said that, you should declare the variable like public $foo = null; in the class declaration, if it's supposed to be a permanent member of the class, to clearly express the intent.
So would you expect this: (code sample) to work?
Yes. It's pretty bad practice (at least it makes my C++ skin crawl), but it wouldn't surprise me in the slightest. See example 2 in the following page for an example of using another class without declaring it beforehand. http://www.php.net/manual/en/language.oop5.basic.php It will throw an error if E_STRICT is enabled.
And does this create these variables on the class instance to be used hereafter?
Yep. Ain't PHP Fun? Coming from a C++/C# background, PHP took a while to grow on me with its very loose typing, but it has its advantages.
That's completely functional, though opinions will differ. Since the creation of the class member variables are in the constructor, they will exist in every instance of the object unless deleted.
It's conventional to declare class member variables with informative comments:
class Example
{
private $data; // array of example data
private $var; // main state variable
public function __construct()
{
$this->data = array();
$this->var = 'something';
}
}
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 am having trouble understanding how to work with objects.
The specific code:
class first{
class second{
public function widgets(){
$a_variable = $a_value;
}
#1
}
$second = new second;
#2
}
#3
$first = new first;
If I initialize $a_variable as $a_variable it is only available inside the function, correct?
If I initialize $a_varialbe as $this->a_variable it is only available inside class second, correct?
Can I initialize $a_variable as $first->second->a_variable? If so, How would I call it at #1, #2, and #3?
Can I initialize $a_varialbe as $this->second->a_variable? If so, How would I call it at #1, #2, and #3?
As you can see I am simply confused as to how OOP works.
First of all, I want to express how much I appreciate all of the help. I have already learned more than enough to consider this question a smashing success.
That said, even if it is poorly formulated, psuedo-code and invalid syntax, this code DOES run.
class class_1{
public function function_1(){
require('class_2.php');
public function function_2_callback(){
//%%%%%% How do I set a variable here and get the DATA...
}
$this->class_2 = new class_2("function_2_callback");
}
}
$class_1 = new class_1;
//&&&&&&&&&& Get the DATA here?
/* CONTENTS OF class_2.php */
class class_2($callback){
call_user_function($callback);
}
Even if we have to look at this as an exercise. Can someone tell me how I would first set (# %%%%%%%)and then call a variable (# &&&&&&&&) as shown?
First off: What you have there doesn't work, you cannot declare a class inside a class the way you are doing (notwithstanding conditionally declaring a class inside a function, which you should not do).
Scope in PHP (including OOP) is very simple:
variables have function scope
object properties are accessible if you have a reference to the object
the visibility of object properties can be restricted
The only real scope you have is function scope for variables:
$a = 'foo';
function bar() {
$a = 'bar';
}
The two $as are entirely unrelated, in different scopes. As simple as that.
class Foo {
public $a = 'foo';
public function bar() {
$this->a; // foo
$a = 'bar';
}
}
$foo = new Foo;
$foo->a; // foo
An object property has no scope, it has visibility. You can access it if you have the object in scope. Above, $foo is the object. It's in scope, its property a is public, therefore it can be accessed using $foo->a. Inside the class, the property is accessible via $this->a.
The $a = 'bar' is a local variable in the function and has nothing to do with $this->a. It is not accessible anywhere except inside the function. Refer to rule #1, function scope.
class Bar {
protected $b = 'bar';
public function baz() {
$this->b; // bar
}
}
$bar = new Bar;
$bar->b; // doesn't work
If the visibility is not public, the property (here b) is not accessible from outside the class itself. Inside the class you can access it using $this->b, but not from outside using $bar->b. It's not about scope, but visibility.
And that's pretty much the scope rules in PHP.
First of all your example is invalid code
PHP does not support nested classes, meaning a class within a class.
if you define a class, a variable initialized within a method is local to that method, while you can "initialize" an attribute with $this->newattribute, you should have declared it and its visibility before (before you write a method public / private / protected $varname = "initial value";).
Your questions 3 and 4 would make sense in another context, this is when an object is passed as member of another object, see example below.
If you build it like
<?php
class First {
public $second;
}
class Second {
public $a_variable;
}
$foo = new First();
$foo->second = new Second();
you can access it:
$foo->second->a_variable = "foo";
or within a method in second with
$this->a_variable;
or within a method in first with
$this->second->a_variable;
You should NOT be nesting classes like that. That shouldn't even run. I would suggest running the code first. There are some tools online for testing small snippets of PHP code, such as this.
For the code to run as you might expected it to, it should look like this:
class second{
public function widgets(){
$a_variable = $a_value;
}
}
class first{
public $second;
public function __construct() {
$this->second = new second;
}
}
$first = new first;
A variable that begins with $[a-z]+ is local to the function. A property beginning with $this->[a-z]+ (where [a-z] is 1 or more letters) is part of the object.
There's some documentation on php.net that goes over the specifics of objects in php here.
If I initialize $a_variable as $a_variable it is only available inside
the function, correct?
Yes, correct. It begins with $[a-z]. Not quite true if you use the global keyword, but that's discouraged.
If I initialize $a_varialbe as
$this->a_variable it is only available inside class second, correct?
Yes, but you should declare it first. You can do this with public $variable, protected $variable or private $variable. public means a property can be accesses from the outside, whereas private means only the class itself can access it. protected is private to the outside, but public to classes that extend from your class.
(public/private/public became available in PHP 5. In PHP 4 you would use var $variable, which defaults to public in PHP 5)
Can I initialize $a_variable as $first->second->a_variable?
You can arbitrarily initialize class variables without declaring them, but that's not something you should be doing.
If so, How would I call it at #1, #2, and #3?
You can't call code there (in your example). Code must be inside a function or in the global context (outside of the class definition).
A Brief Explanation of Classes
class foo{
// This can be accessed anywhere
public $i_am_public;
// This can be accessed within this class and any sub classes
protected $i_am_protected;
// Thi can only be accessed within this class
private $i_am_private;
// This function can be accessed anywhere
public function foo_function(){
// This variable is only available in this function
// it cannot be accessed anywhere else
$variable = 'Hello World';
// However, you can access any of the other variables listed above
// like so
$this->i_am_public = 'public';
$this->i_am_protected = 'protected';
$this->i_am_private = 'private';
// Write these variables
echo $this->i_am_public;
echo $this->i_am_protected;
echo $this->i_am_private;
}
}
$foo = new foo;
$foo->foo_function();
// You can change any publicly defined variables outside
// of the class instance like so
$foo->i_am_public = 'testing';
Specific Answers to Questions
Before I go any further, I would hugely urge you not to define a class within a class! Instead, use class extensions which I will explain later. In fact, I am surprised your code even works!
If I initialize $a_variable as $a_variable it is only available inside
the function, correct?
Yes, this will only be available inside the function. If you want to access it outside of the function then you need to define it outside the function using one of the scope definitions public, protected, private.
If I initialize $a_varialbe as $this->a_variable it is only available
inside class second, correct?
This depends on what scope you give it, but you shouldn't be defining a class within a class anyway.
Can I initialize $a_variable as $first->second->a_variable? If so, How
would I call it at #1, #2, and #3?
I cannot answer this as I have never nested a class within a class, once again I would urge you to change this structure.
Can I initialize $a_varialbe as $this->second->a_variable? If so, How
would I call it at #1, #2, and #3?
Please see above answer :-)
Nesting Classes
As mentioned, I have never seen this before, and I am surprised it even works. You should definitely change this structure.
One suggestions would be to use extensions like so:
class foo{
// This can be accessed anywhere
public $i_am_public;
// This can be accessed within this class and any sub classes
protected $i_am_protected;
// Thi can only be accessed within this class
private $i_am_private;
public function foo_function(){
echo 'Hello World';
}
}
class bar extends foo {
// This is a public function
public function baz(){
// These will work
$this->i_am_public = 'public';
$this->i_am_protected = 'protected';
// This will not work as it is only available to
// the parent class
$this->i_am_private = 'private';
}
}
// This will create a new instance of bar which is an
// extension of foo. All public variables and functions
// in both classes will work
$bar = new bar;
// This will work because it is public and it is inherited
// from the parent class
$bar->foo_function();
// This will work because it is public
$bar->baz();
I've been looking at some code and am having a hard time working out variable declaration in php classes. Specifically it appears that the code i'm looking at doesn't declare the class variables before it uses them. Now this may be expected but I can't find any info that states that it is possible. So would you expect this:
class Example
{
public function __construct()
{
$this->data = array();
$this->var = 'something';
}
}
to work? and does this create these variables on the class instance to be used hereafter?
This works the same as a normal variable declaration would work:
$foo = 'bar'; // Created a new variable
class Foo {
function __construct() {
$this->foo = 'bar'; // Created a new variable
}
}
PHP classes are not quite the same as in other languages, where member variables need to be specified as part of the class declaration. PHP class members can be created at any time.
Having said that, you should declare the variable like public $foo = null; in the class declaration, if it's supposed to be a permanent member of the class, to clearly express the intent.
So would you expect this: (code sample) to work?
Yes. It's pretty bad practice (at least it makes my C++ skin crawl), but it wouldn't surprise me in the slightest. See example 2 in the following page for an example of using another class without declaring it beforehand. http://www.php.net/manual/en/language.oop5.basic.php It will throw an error if E_STRICT is enabled.
And does this create these variables on the class instance to be used hereafter?
Yep. Ain't PHP Fun? Coming from a C++/C# background, PHP took a while to grow on me with its very loose typing, but it has its advantages.
That's completely functional, though opinions will differ. Since the creation of the class member variables are in the constructor, they will exist in every instance of the object unless deleted.
It's conventional to declare class member variables with informative comments:
class Example
{
private $data; // array of example data
private $var; // main state variable
public function __construct()
{
$this->data = array();
$this->var = 'something';
}
}