Create a new copy of object itself with some new properties - php

Sometimes it's difficult to explain in human language what you want to do in programming, but I will try...
Please explain to me, how can I implement the following logic. Suppose we have a template class:
$obj1=new Tmpl($somevar1, $somevar2, ...);
//we then add a new file to template
//as we don't have any files yet, new object won't created
$obj1->AddTmpl('file1.tmpl');
//we add a second file to template,
//it will be independent template
//but all properties from $obj1 must be available
$obj2=$obj1->AddTmpl('file2.tmpl');
$obj1->printTmplFile(); //should output file1.tmpl
$obj2->printTmplFile(); //should output file2.tmpl
$obj2->printInitialVars();
//will print $somevar1, $somevar2 constructed for $obj1;
//$obj1 of course must have these variables available also
So, the purpose of it is in creating new object for each new file of a template. Each new object should have all set of properties which have been established for old object. So, in this case, for example, we will not call a constructor each time with the same arguments. Also only $obj1 can create a copy of itself. And if it is first call to method AddTmpl, then we don't create new copy.

(Here I assume that the AddTmpl function does not return a copy of the object itself.)
The following line is wrong. You are saving the result of the AddTmpl function into $obj2, this does not return a copy of $obj1.
$obj2=$obj1->AddTmpl('file2.tmpl');
You have to use cloning like this:
$obj2 = clone $obj1;
$obj2->AddTmpl('file2.tmpl');
Note that after the cloning, $obj2 and $obj1 are totally independant and any changes made to one will not be reflected to the other. This is the intended purpose!
More information about cloning: http://php.net/manual/en/language.oop5.cloning.php
Edit: fixed typo in code

I'm not sure if it's what you're trying to do, but have a look at php's object cloning.

Possible yes, (with clone in the addTmpl() function)
But thats not adviseable, the API you're showing in the question not directly understandable / selfexplanatory.
Other solutions are:
$tpl = new Tmpl();
$tpl->render('template1.tmpl');
$tpl->render('template2.tmpl');
Or
$tpl = new Tmpl();
$tpl->setTmpl('template1.tmpl');
$tpl2 = clone $tpl;
$tpl2->setTmpl('template2.tmpl');
$tpl1->render();
$tpl2->render();

Related

Why changes on a class affects on other class?

Here is my code: Demo
class myclass1 {
public $myvariable;
}
$obj1 = new myclass1;
$obj2 = $obj1;
$obj1->myvariable = 'something';
echo $obj2->myvariable; //=> something
As you see, I've initialized something to the first object, but surprisingly it will be also applied on the second object. Why really? Actually I need to have two different value in $myvariable for both classes, not the same value.
How can I do that?
That's how OOP works. Actually all you need to know is about pass-by-reference. Take a look at this:
In your code, both $obj1 and $obj2 are using same memory point. So any change on $obj1 will be seen also on the $obj2. To separate them from each other you need to use clone:
$obj2 = clone $obj1;
By cloning an object you are actually making a copy of it. So the new object won't refer to the old one.

Copy/clone parts of an object?

I have an object $stdClassObject that's created by json_decode. It's for train schedules. I need to be able to create a new object which contains just those trains heading east bound. I'm at a loss of how to do this since I'm very new to Objects in PHP. Here is the PHP code I've isolate $trips[$ny_trip]:
// $stdClassObject originally created by json_decode
foreach ($trips as $ny_trip=>$ny_trip_info) {
if (East_Bound($ny_trip_info->DESTINATION)) {
// Copy or clone(?) $trips[$ny_trip]) to an object called east_bound
...
}
}
I see two options:
Implement the magic method __clone() to be able to customize the process of cloning
Add a custom function for this to your class. Like YourClass::customClone($options)
Looks like that the first option suites very well here

prevents a class unsetting in 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.

Creating new object with dynamic variables in PHP

I want to create a new object using this
$procedure = new ${$s.'\\'.$p};
It doesn't work. Why isn't this possible?
Why don't you
$name = "$s\\$p";
$procedure = new $name;
?
Also ${$s.'\\'.$p} means a variable, with a variable name that is clearly not good. If you are, and I think you are, trying to get something like an instance of Namespace\Class you should try with the code below.
I think that the {} shortcut only works with this syntax ${} which is clearly referring to a variable. So you cannot use it for instantiating new objects.

Stop new object from updating with old object's variables

I'm trying to do something like:
$obj2 = $obj1
where $var1 is an object, the problem is that I want $obj2 to be like a snap shot of $obj1 - exactly how it is at that moment, but as $obj1's variables change, $obj2's change as well. Is this even possible? Or am I going to have to create a new "dummy" class just so I can create a clone?
Simply clone the object, like so:
$obj2 = clone $obj1;
Any modifications to the members of $obj1 after the above statement will not be reflected in $obj2.
Objects are passed by reference in PHP. This means that when you assign an object to new variable, that new variable contains a reference to the same object, NOT a new copy of the object. This rule applies when assigning variables, passing variables into methods, and passing variables into functions.
In your case, both $obj1 and $obj2 reference the same object, so modifying either one will modify the same object.

Categories