PHP Static class variables, inheritance, and garbage collection - php

I am having some memory problems with a script that uses objects set up with inherited static variables like this.
class a
{
public static $a = "a";
}
class b extends a
{
private $instanceVar = 'hey';
private $otherVar = 'you';
public function DoStuff()
{
echo self::$a;
}
}
then code that uses the classes like this
while(condition)
{
$obj = new b();
$obj -> DoStuff();
unset($obj);
}
My question is, will unsetting obj trigger garbage collection and the unsetting of its instance variables since it also holds a reference to the the inherited static variable?

unset in this code doesn't bring anything.
With and without it the object will be successfully collected when it's possible.
will unsetting obj trigger garbage collection
Not it won't. Garbage collector will be called automatically when it makes sense.
since it also holds a reference to the the inherited static variable
It doesn't. Objects don't hold references to a static properties.

If you care so much about GC and have PHP >= 5.3.0 have a look to
gc_collect_cycles and garbage collection in general

Related

The PHP unset doesn't clear the reference completely

I have a simple class and assign its instance to its static variable. When I unset the instance, not sure why it doesn't actual release the memory.
class Foo {
public static $app;
public function __construct() {
self::$app = $this;
}
}
$foo = new Foo;
unset($foo);
var_dump($foo);
var_dump(Foo::$app);
Result:
Warning: Undefined variable $foo in /var/www/index.php on line 16
NULL object(Foo)#1 (0) { }
Obviously, the static $app point to the itself instance, we have unset the instance but doesn't really clean the memory for this variable. Why did it happen? Are the instance of the $app and the $foo different ones?
$foo and Foo::$app point to the same object as you desire. Any changes in terms of object properties will reflect either way if you do it.
This is because they point to the same copy in the memory as expected. However, PHP maintains a refcount indicating how many references to that memory location is present.
So, when you use unset($foo);, it doesn't garbage collect that memory location(and the value inside it), but rather just decreases the refcount of it. This can be proved using debug_zval_dump and PHP achieves the refcount maintenance using copy on write mechanism as mentioned in the linked doc.
Hence, unsetting $foo doesn't destroy the object itself but rather just the refcount and removes the variable from memory since the object still holds other references.
Snippet:
<?php
class Foo {
public static $app;
public function __construct() {
self::$app = $this;
}
}
$foo = new Foo;
var_dump($foo === Foo::$app);
debug_zval_dump(Foo::$app);
$foo = 90;// variable modified, copy on write mechanism done internally for Foo::$app, refcount modified
debug_zval_dump(Foo::$app);
Online Demo
You've only unset a reference to an object of class Foo, and that object will get garbage-collected next time garbage collector runs.
Classes, once loaded, live in the memory until request is terminated, and so will their static properties. If they hold a pointer to an object, that object won't be garbage-collected. If you want to garbage-collect Foo::$app, you'll need to unset it too.

How does Singleton pattern stay in memory throughout the lifetime of the program?

I have the following code:
//init X (DB initialization with credentials)
$x = MySqlConnector::getMySql();
//I destroy $x
unset($x);
$x = null;
//I try to re-initialize the database, but it is already initialized
//as evident from my logs
$x = MySqlConnector::getMySql();
Relevant function:
public static function getMySql()
{
if (null === static::$instance)
{
include 'include/config.php';
static::$instance = new MySql(DBHOST, DBUSER, DBPASS);
}
return static::$instance;
}
That tells me that even after I kill off the variable that was holding the initialized object, somehow MySqlConnector stayed in memory.
How? I don't think it works with any other non-static class.
Static properties exist in the global scope, and are not associated to any particular instance.
You may be unsetting $x, but MySqlConnector::$instance stays defined.
Typically, in this kind of scenario, $instance will be a private static, so you wont be able to access the property directly, only through accesor methods, hence guaranteeing that only the Singleton class will have access to modify the property, and you wont be changing/setting/unsetting it but through properly defined methods, if they exist.
More info in the manual.

About scope and OOP in PHP

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();

Which is better in PHP, Static Variable or Private Variable?

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.

Purpose of PHP constructors

I am working with classes and object class structure, but not at a complex level – just classes and functions, then, in one place, instantiation.
As to __construct and __destruct, please tell me very simply: what is the purpose of constructors and destructors?
I know the school level theoretical explanation, but i am expecting something like in real world, as in which situations we have to use them.
Provide also an example, please.
Regards
A constructor is a function that is executed after the object has been initialized (its memory allocated, instance properties copied etc.). Its purpose is to put the object in a valid state.
Frequently, an object, to be in an usable state, requires some data. The purpose of the constructor is to force this data to be given to the object at instantiation time and disallow any instances without such data.
Consider a simple class that encapsulates a string and has a method that returns the length of this string. One possible implementation would be:
class StringWrapper {
private $str;
public function setInnerString($str) {
$this->str = (string) $str;
}
public function getLength() {
if ($this->str === null)
throw new RuntimeException("Invalid state.");
return strlen($this->str);
}
}
In order to be in a valid state, this function requires setInnerString to be called before getLength. By using a constructor, you can force all the instances to be in a good state when getLength is called:
class StringWrapper {
private $str;
public function __construct($str) {
$this->str = (string) $str;
}
public function getLength() {
return strlen($this->str);
}
}
You could also keep the setInnerString to allow the string to be changed after instantiation.
A destructor is called when an object is about to be freed from memory. Typically, it contains cleanup code (e.g. closing of file descriptors the object is holding). They are rare in PHP because PHP cleans all the resources held by the script when the script execution ends.
Learn by example:
class Person {
public $name;
public $surname;
public function __construct($name,$surname){
$this->name=$name;
$this->surname=$surname;
}
}
Why is this helpful? Because instead of:
$person = new Person();
$person->name='Christian';
$person->surname='Sciberras';
you can use:
$person = new Person('Christian','Sciberras');
Which is less code and looks cleaner!
Note: As the replies below correctly state, constructors/destructors are used for a wide variety of things, including: de/initialization of variables (especially when the the value is variable), memory de/allocation, invariants (could be surpassed) and cleaner code.
I'd also like to note that "cleaner code" is not just "sugar" but enhances readability, maintainability etc.
The constructor is run at the time you instantiate an instance of your class. So if you have a class Person:
class Person {
public $name = 'Bob'; // this is initialization
public $age;
public function __construct($name = '') {
if (!empty($name)) {
$this->name = $name;
}
}
public function introduce() {
echo "I'm {$this->name} and I'm {$this->age} years old\n";
}
public function __destruct() {
echo "Bye for now\n";
}
}
To demonstrate:
$person = new Person;
$person->age = 20;
$person->introduce();
// I'm Bob and I'm 20 years old
// Bye for now
We can override the default value set with initialization via the constructor argument:
$person = new Person('Fred');
$person->age = 20;
$person->introduce();
// if there are no other references to $person and
// unset($person) is called, the script ends
// or exit() is called __destruct() runs
unset($person);
// I'm Fred and I'm 20 years old
// Bye for now
Hopefully that helps demonstrate where the constructor and destructor are called, what are they useful for?
__construct() can default class members with resources or more complex data structures.
__destruct() can free resources like file and database handles.
The constructor is often used for class composition or constructor injection of required dependencies.
The constructor of a class defines what happens when you instantiate an object from this class. The destructor of a class defines what happens when you destroy the object instance.
See the PHP Manual on Constructors and Destructors:
PHP 5 allows developers to declare constructor methods for classes. Classes which have a constructor method call this method on each newly-created object, so it is suitable for any initialization that the object may need before it is used.
and
PHP 5 introduces a destructor concept similar to that of other object-oriented languages, such as C++. The destructor method will be called as soon as all references to a particular object are removed or when the object is explicitly destroyed or in any order in shutdown sequence.
In practise, you use the Constructor to put the object into a minimum valid state. That means you assign arguments passed to the constructor to the object properties. If your object uses some sort of data types that cannot be assigned directly as property, you create them here, e.g.
class Example
{
private $database;
private $storage;
public function __construct($database)
{
$this->database = $database;
$this->storage = new SplObjectStorage;
}
}
Note that in order to keep your objects testable, a constructor should not do any real work:
Work in the constructor such as: creating/initializing collaborators, communicating with other services, and logic to set up its own state removes seams needed for testing, forcing subclasses/mocks to inherit unwanted behavior. Too much work in the constructor prevents instantiation or altering collaborators in the test.
In the above Example, the $database is a collaborator. It has a lifecycle and purpose of it's own and may be a shared instance. You would not create this inside the constructor. On the other hand, the SplObjectStorage is an integral part of Example. It has the very same lifecycle and is not shared with other objects. Thus, it is okay to new it in the ctor.
Likewise, you use the destructor to clean up after your object. In most cases, this is unneeded because it is handled automatically by PHP. This is why you will see much more ctors than dtors in the wild.
I've found it was easiest to grasp when I thought about the new keyword before the constructor: it simply tells my variable a new object of its data type would be give to him, based on which constructor I call and what I pass into it, I can define to state of the object on arrival.
Without the new object, we would be living in the land of null, and crashes!
The Destructor is most obvious from a C++ stand point, where if you dont have a destructor method delete all the memory pointed to, it will stay used after the program exits causing leaks and lag on the clients OS untill next reboot.
I'm sure there's more than enough good information here, but another angle is always helpful from what I've noticed!
constructor is function of class which is executed automatically when object of class is created we need not to call that constructor separately we can say constructor as magic method because in php magic method begin with double underscore characters

Categories