prevents a class unsetting in php - php

I created a class implementing ArrayAccess and I added it a function to prevents WRITE actions:
$Obj->Add("key","something");
$Obj->Add("key2","something2");
$Obj->SetReadOnly(); // sets read only property
unset($Obj["key2"]); // throws error, object is readonly
But, i want to prevent unsetting object too:
unset($Obj);
I can do it?I hear suggestions.
Thanks for help!.

I can't imagine any situation where you would really want to do this. I can also imagine doing this will cause you serious problems at script termination when all objects are destroyed. The PHP manual says the following on throwing exceptions in destructors:
Note:
Attempting to throw an exception from a destructor (called in the time
of script termination) causes a fatal error.
The above statement implies that you can throw an exception if you're not in the script termination phase, so maybe the following is possible.
public function __destruct ()
{
if ($this -> isReadOnly ())
{
throw new Exception ('Class is read-only');
}
}
However, as the manual points out, this will trigger a fatal error during script shutdown.
I honestly can't see any point to wanting to prevent object destruction. It should be up to the programmer to manage object lifetimes.

unset() does not actually destruct an object, if that's what you're trying to prevent.
An object will only be destructed when all references to it have been unset or are no longer in scope. Even then it won't happen until the garbage collector runs.
So if you have some code that you are worried will molest your object, you've already done a good job of making it immutable with your read-only logic.
Let's say you have
$Obj = gotMyObjectSomehow();
and you need to pass it to a some other code you don't want to unset $Obj. As long as that code is called inside a function, there's nothing to be concerned about. If you call
someFunction($Obj);
and let's say that function unsets the parameter it's passed in
function someFunction($anObj) {
unset($anObj);
}
then your original $Obj variable will still be set.
The function creates a second variable referencing the original object and uses that in its own scope.

You can't control unsetting variable names, because those names are not technically a part of the object referenced. Consider the following:
$a = new MyObject();
$b = $a;
Now you have two references to the same object. There is no difference between using $a and $b, because in PHP objects are always used by reference (i.e. you don't have to do $b =& $a in the second line). So both $a and $b are essentially the same object; unsetting $a will not destroy the object, as well as unsetting $b won't destroy it; all references need to be unset before the object is destroyed.

I don't think you can do what you're asking for - it's not possible to prevent a variable being unset like that.
However, a comment of yours above set me thinking. You said:
.... idea if you want to prevent unsets system variables in a thirdparty extensions
So if I understand you right, your aim here is to ensure that while the thirdparty code (ie your software) is in use, all the variables associated with it remain in place?
Now you haven't specified much about what variables there are in this system. We see one object in the question, but presumably there must be more than that? I'm guessing you've got a bunch of things that tie together, right? It would help in these sorts of questions to provide a bit more context; the actual thing that you're asking for isn't possible, but with a bit of understanding about what you want to achieve, we could come up with alternatives.
Okay. So my suggestion: create your objects as Singletons. This is often frowned on by purists, but might work well for this situation, depending on exactly what you're doing. The beauty here is that you can encapsulate all access to the object inside class methods, meaning that the developer using your code doesn't have access to the master copy of the object in order to unset it.
A singleton works like this:
<?php
class mySingletonClass {
private static $masterObject=null;
public static function getInstance() {
if(!isset(self::$masterObject)) {
self::$masterObject = new self;
}
return self::$masterObject;
}
private function __construct() {
//your existing constructor, as it already exists, but marked as private.
}
//...and all the other methods as you already have them.
}
The class constructor method is private, so can only be accessed from methods within the class. Therefore, you can no longer do new classname(). The only way you can get an object of this class is to get it from the static getInstance() method. And the key thing here is that this method always returns the same copy of the object.
$obj = mySingletonClass::getInstance();
unset($obj);
$obj = mySingletonClass::getInstance(); //will give the exact same object as the first time.
You can unset it if you want, but the original object is still there and can still be accessed. Any of your other classes can use that getInstance() method to get the same copy of the same object from anywhere in the program. It's an indestructible global variable.
Singletons are often used for a program's main database connection object, but it might be a useful pattern for you here.
I hope that helps. It's about the only way I can think of to get close to what you want.

Related

Passing objects across multiple nested classes

I'm running into a problem when passing an object across different classes and trying to have only one instance of it instead of multiple clones.
TLDR version:
If I have objects A->B->C, where C gets passed A by way of B as a parameter on creation, will C->A->B access the original B that had created it, or a copy of that B? How many copies of B are there in the system memory now?
Slightly more detailed version:
Let's say I have a (perhaps overly convoluted) nested class structure for handling a server-based request. The first step is to instantiate an object of class Session, and then within it, create an object $handler of class Handler. However, as $handler will need to have access to the internal attributes of $session (and multiple other objects created within it, like $user or $database, whose purposes ought to be self-explanatory), I then pass it on as a parameter:
class Session {
public $handler;
public function __construct() {
$this->handler = new Handler( $this );
//DO STUFF HERE
}
}
The Handler class inherits the session like this:
class Handler {
private $session;
public function __construct( Session $inherited_session ) {
$this->session = $inherited_session;
}
}
Side note: $session is set to private to avoid even the slightest chance of infinite loops down the line, of the $this->session->handler->session->handler variety.
Now, according to my understanding and all the research I've done, PHP passes objects by reference, so the $this->session object within this Handler ought to be accessing the same object in the system memory as the original session? Not a copy of itself?
Yet here's my problem. Suppose now I create a third-level nested object within the Handler class, of class Dashboard, and want to pass the original $session to it (not, mind it, just the Handler object itself). Off we go, so we put this somewhere within the Handler class:
$dashboard = new Dashboard( $this->session );
The Dashboard constructor inherits the session in exactly the same way as Handler did:
class Dashboard {
private $session;
public function __construct( Session $inherited_session ) {
$this->session = $inherited_session;
}
}
However, it doesn't seem able to access the instance of Handler that had called it, and by now it appears that we have multiple copies of $session and $handler floating about - and I'd very much like to understand why, because it contradicts everything I understand about references.
Here's an example of this pathological behaviour - say we have a variable in Handler:
public $temp_var;
that the constructor of Handler assigns a value:
$this->temp_var = '123';
and then we try accessing it from within the Dashboard class as $this->session->handler->temp_var. That returns NULL. Why? Did $dashboard inherit a copy of $session on initialisation that doesn't have an initialised ->handler to call on? How can I make it so there is only one (unique) object of each class, and updating the internal (public) variables of $handler would get correctly passed on to $dashboard->session->handler? Or am I just making some obvious / idiotic mistake somewhere and completely not seeing it?
Note #1: any variable set in $session as $this->var is correctly accessible from $dashboard->session->var, so double-level nesting works as expected; it's triple-level one that doesn't.
Note #2: I've already thought of simply passing $handler as a parameter to all of its nested objects along with $session (and if no solution exists, this is what I'll have to do), but it doesn't solve the original problem of $this->session->handler being somehow and inexplicably different from the original $handler within its nested objects.
Oh, and my thanks to anyone who managed to read through all this!
As far as I understand, you're dealing with composition not with inheritance here.
So, you have a Session which is passed to a Handler, the Handler and Dashboard both "know" the session through composition (keeping a reference on the private variable).
I don't understand why do you need this sort of circular reference, but if you want to access the Handler from Dashboard, why not passing the Handler to it?
Besides that, it looks like you are storing the handler in a local scoped variable (I've been away from PHP the last two years, but...)
class Session {
public function __construct() {
// isnt $this->handler = new Handler( $this ) ??
$handler = new Handler( $this );
}
}
From a conceptual point of view, there's not "nesting", only references, so I dont think that the "three levels" does anything to do with that.
Hope it helps!
Here's an example I've modified the Session and privacy just to verify that the $session is still the same

Why is it possible to access private variables from outside class by reference?

If I have a public class method that is returning a reference to a non-visible (private or protected) property, I can use that reference to gain direct access:
PHP code
class A
{
private $property = 'orange';
public function &ExposeProperty()
{
return $this->property;
}
public function Output()
{
echo $this->property;
}
}
$obj = new A();
# prints 'orange'
$obj->Output();
$var = &$obj->ExposeProperty();
$var = 'apple';
# prints 'apple'
$obj->Output();
Is there a reasoning behind this functionality in PHP? Or is it just a design oversight, failing to keep track of access violations through references?
It obviously comes in handy when you want to achieve something like:
PHP code
$this->load->resource();
Where load is an object that modifies given properties of $this. But apart from this shortcut, I don't see many possible uses which wouldn't be possible with valid OOP patterns otherwise.
Well, you are explicitly returning a reference to a value. You're locking the front door, but are then opening a side entrance. You are very deliberately taking aim and shooting your own foot here. If $property was an object, and you'd return this object with or without & reference, any modifications to this object would be reflected on $property as well. That's how a reference works, it always modifies the one and only existing value that the reference points to.
Visibility modifiers aren't magic iron clad "protections". There are any number of ways how you can circumvent a private visibility to access and modify the property. They're mostly there as a flag to yourself and other developers that this property should not be accessed directly, it's for internal use and not a publicly sanctioned API. And PHP will slap you on the wrist should you forget that. Nothing more, nothing less.
Also, nothing is really being violated here. Outside code is at no point accessing or modifying $obj->property. That's the only thing private is supposed to prohibit. You're essentially exposing a public API on your object which modifies a private property. Usually this is done with getter and setter functions, but a by-reference API obviously works as well.

Is there any point to unset($this) in destructor?

I came across one class and what cought my attention right away was this:
public function __destruct() {
unset($this);
}
My first thought was that this is just plain stupidity, it fact it looked so idiotic that I thought that either there really is a good reason to do this or the author is just clueless
Any thoughts? Any reasons to do this?
Short answer: No
Long answer: Noooooooooooooooooooooo
My first thought was that this is just plain stupidity, it fact it looked so idiotic that I
thought that either there really is a good reason to do this or the author is just clueless.
The latter, I'm afraid: there is no point in unsetting an instance on destruct. It might be the original programmer is a big fan of being explicit, but the worst thing is that this doesn't even work:
<?php
class Foo {
function __destruct( ) {
unset( $this );
}
}
$foo = new Foo;
$foo->__destruct( );
var_dump( $foo );
Given that the destructor is only invoked on an unset($object) or garbage collection of unreferenced objects, the usefulness of an inner unset($this) is quite self explanatory.
In particular it will have no effect itself, because it only clears the name reference $this. It does not free the occupied memory, which happens after the destructor is left.
In contrast it is sometimes sensible to use:
unset($this->subobject);
Which is probably what the author here misremembered and misapplied.
No real point that I can think of. Maybe ask the developer about it.
I can't see the point of this, considering the triggers for the __destruct method to be called. From http://www.php.net/manual/en/language.oop5.decon.php:
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.
Also note that it probably wouldn'd do what you expect even if the __destruct method was called manually. From http://php.net/manual/en/function.unset.php:
It is not possible to unset $this inside an object method since PHP 5.
Some testing reveals that all this will do is remove the current $this reference to the object within the __destruct method.
Found this on the internet.
unset($this) will only remove $this from variable space of the
current function scope. The object will remain in the caller scope.
You can do a $this = null to overwrite the object however.
http://bytes.com/topic/php/answers/459538-oop-unset-maybe-unset#post1762212

PHP constructor uses? [duplicate]

In my quest in trying to learn more about OOP in PHP. I have come across the constructor function a good few times and simply can't ignore it anymore. In my understanding, the constructor is called upon the moment I create an object, is this correct?
But why would I need to create this constructor if I can use "normal" functions or methods as their called?
cheers,
Keith
The constructor allows you to ensure that the object is put in a particular state before you attempt to use it. For example, if your object has certain properties that are required for it to be used, you could initialize them in the constructor. Also, constructors allow a efficient way to initialize objects.
Yes the constructor is called when the object is created.
A small example of the usefulness of a constructor is this
class Bar
{
// The variable we will be using within our class
var $val;
// This function is called when someone does $foo = new Bar();
// But this constructor has also an $var within its definition,
// So you have to do $foo = new Bar("some data")
function __construct($var)
{
// Assign's the $var from the constructor to the $val variable
// we defined above
$this->val = $var
}
}
$foo = new Bar("baz");
echo $foo->val // baz
// You can also do this to see everything defined within the class
print_r($foo);
UPDATE:
A question also asked why this should be used, a real life example is a database class, where you call the object with the username and password and table to connect to, which the constructor would connect to. Then you have the functions to do all the work within that database.
The idea of constructor is to prepare initial bunch of data for the object, so it can behave expectedly.
Just call a method is not a deal, because you can forget to do that, and this cannot be specified as "required before work" in syntax - so you'll get "broken" object.
Constructors are good for a variety of things. They initialize variables in your class. Say you are creating a BankAccount class. $b = new BankAccount(60); has a constructor that gives the bank account an initial value. They set variables within the class basically or they can also initialize other classes (inheritance).
The constructor is for initialisation done when an object is created.
You would not want to call an arbitrary method on a newly created object because this goes against the idea of encapsulation, and would require code using this object to have inherent knowledge of its inner workings (and requires more effort).

Benefits of using a constructor?

In my quest in trying to learn more about OOP in PHP. I have come across the constructor function a good few times and simply can't ignore it anymore. In my understanding, the constructor is called upon the moment I create an object, is this correct?
But why would I need to create this constructor if I can use "normal" functions or methods as their called?
cheers,
Keith
The constructor allows you to ensure that the object is put in a particular state before you attempt to use it. For example, if your object has certain properties that are required for it to be used, you could initialize them in the constructor. Also, constructors allow a efficient way to initialize objects.
Yes the constructor is called when the object is created.
A small example of the usefulness of a constructor is this
class Bar
{
// The variable we will be using within our class
var $val;
// This function is called when someone does $foo = new Bar();
// But this constructor has also an $var within its definition,
// So you have to do $foo = new Bar("some data")
function __construct($var)
{
// Assign's the $var from the constructor to the $val variable
// we defined above
$this->val = $var
}
}
$foo = new Bar("baz");
echo $foo->val // baz
// You can also do this to see everything defined within the class
print_r($foo);
UPDATE:
A question also asked why this should be used, a real life example is a database class, where you call the object with the username and password and table to connect to, which the constructor would connect to. Then you have the functions to do all the work within that database.
The idea of constructor is to prepare initial bunch of data for the object, so it can behave expectedly.
Just call a method is not a deal, because you can forget to do that, and this cannot be specified as "required before work" in syntax - so you'll get "broken" object.
Constructors are good for a variety of things. They initialize variables in your class. Say you are creating a BankAccount class. $b = new BankAccount(60); has a constructor that gives the bank account an initial value. They set variables within the class basically or they can also initialize other classes (inheritance).
The constructor is for initialisation done when an object is created.
You would not want to call an arbitrary method on a newly created object because this goes against the idea of encapsulation, and would require code using this object to have inherent knowledge of its inner workings (and requires more effort).

Categories