I have a global object, a "registry", it is a container with other important objects:
Input object.
Output object.
DB object with connection.
Logging object.
Session object.
I need to have this global object in every place (object), where I process my request.
Like in my JBoss environment, where I have one Stateful Session Bean as a front controller, which directs the processing to a special Stateless Session Bean, I have one entry point, "facade.php".
In this facade.php, I create the global object and place the other objects (input object, ...) into it.
Then there is a large switch statement, where I redirect the request to special processing objects.
Is there a method, mechanism, to have access to this general object from the processing objects without handing it over as a parameter?
To have a variable available everywhere you can use a $_SESSION variable like so:
session_start();
$_SESSION['registry'] = // Your data
Make sure to use the session_start() function whenever you want access to the session variables.
What you can do:
put the Object into the Session. http://php.net/manual/en/book.session.php (but this will survive "requests")
Make the Object a singleton. http://en.wikipedia.org/wiki/Singleton_pattern (i recommend this, if its suitable for the situation. don't just use singletons to avoid passing parameters to classes/functions.)
Mark the Object with the global keyword. http://php.net/manual/en/language.variables.scope.php
Related
I want to know when an object in PHP will be destruct (destroy) by default. For example if we instantiate a class in a function, does it destruct at the end of function or still will be alive ?
It will eventually be destroyed when all variables that point to the object cease to exist. Variables cease to exist when they go out of scope or when they are unset. Variables go out of scope when the scope/function they were declared in exits.
Yes, it will. The object will live for the duration that it's instance is in scope. You may wish to browse the PHP Garbage Collection documentation. It's also worth noting that you can try these things out for yourself by implementing a __destruct magic method.
So lets say I have a class that is composed of other classes.
class HttpRequest
{
public $session = new Session();
// .. the rest of the HttpRequest code
}
Now, I want to have access to Session class through HttpRequest class so Im using composition.
But does this breaks laws of OOP Encapsulation or Data hidding that states that all properties should be protected, and accessed through setter and getter methods?
Is this wrong:
$request = new HttpRequest();
$request->session->set('id', 5);
or should I use this:
$request = new HttpRequest();
$session = $request->getSession();
$session->set('id', 5);
Encapsulation states that properties shoud be protected.
How to provide access to inner classes then? Is the first example wrong as far as proper OOP goes?
There are valid reasons to not allow direct access to the object:
Allows for manipulation of the object outside of the object itself. If you make the property public, any part of your code could overwrite $session on the HttpRequest class, and you'd have a tough time tracking it down. Encapsulation from a data protection standpoint is there to ensure that only the object's methods can directly alter the object.
Allows you to gracefully handle the case in which that variable is not set. If, for some reason, $session does not get set on your class - you'll immediately have a fatal when you try to call a method on it. If you wrap it in a getter, you could check for that condition and create a new instance of the class on the fly.
Follows true "OO" paradigms
However, in some cases I would say it is okay to do this. Particularly if you know that the property will always be set (and the only way in which it would not be set is not a supported way to use the object).
It also makes sense depending on how the property is going to be accessed. Symfony2 uses this in their Request classes. It feels natural in that case, as the "query" "post" and "request" vars are all "ParameterBag"s (glorified arrays). However, they do expose a getter for the Session object - likely because of it's use case.
In short: it really depends on how you'll be using the variable. In this particular case, I'd say it doesn't much matter.
I like your first option, (It's the one using composition), and look that has encapsulation (I don't know what makes the function set), but I suppose that it's modifying some attribute through the function of the "component" object "session", that pattern is also known as "delegation".
On the other hand if you use encapsulation you cannot user "public", that is allowing to be modified for everybody. It's because of this that you user setters or getter, or in your code "set"
I know this is old, but I would use neither of these. Does your HttpRequest object really need to hold onto the Session object or can a Session object be passed into some functions of the HttpRequest object that need it? Is there a strong case for having HttpRequest store this object?
Maybe I'm just not seeing it, but is there any other way to access a previously created session namespace, other than calling $_SESSION directly? Besides the fact that I really don't want to do this, the Zend documentation also advises against this:
while $_SESSION is still available in
PHP's global namespace, developers
should refrain from directly accessing
it, so that Zend_Session and
Zend_Session_Namespace can most
effectively and securely provide its
suite of session related
functionality.
The Zend_Session_Namespace class doesn't have a static method for getting a namespace, and although the now deprecated namespaceGet method in Zend_Session instructs me to use Zend_Session_Namespace#getIterator, that method is not static.
So that means I need to initialize a new namespace, using the new keyword. The problem is, this doesn't include previously set variables:
$ns = new Zend_Session_Namespace('foo');
$ns->foo = 'bar';
On a subsequent request, this:
print_R(new Zend_Session_Namespace('Foo'));
...prints this:
Zend_Session_Namespace Object
(
[_namespace:protected] => Foo
)
which seems obvious.
So how am I supposed to fetch the previously created namespace, without using $_SESSION['Foo']?
The case of your two code examples doesn't match (foo vs. Foo), I'm not sure if that was just a typo or not. Zend_Session_Namespace is just a wrapper for $_SESSION, so all you need to do is create a namespace object with the same key and then all your data should be available.
$ns = new Zend_Session_Namespace('foo');
$ns->foo = 'bar';
and then on another page:
$ns = new Zend_Session_Namespace('foo');
echo $ns->foo; // should output bar
if this doesn't work then there is a problem with your session configuration.
This is probably a noob question, so please be kind.
I'm trying to implement a cache on an expensive "activity" object. In the constructor I first check the cache to see if this Activity instance already exists. If not, I do all the queries to build up the object, serialize it and save it to cache. The next time I come in, I check the cache and my object is there, so I unserialize it. Now is my problem, how do I put that object into $this, the current object? I can't just say "$this = unserialize($row[0]);" That fails with the error message, "Cannot re-assign $this in ActivityClass.php". What am I missing?
Thanks a ton!
Mike
If you don't want your construction to leave the class, you can create a factory method:
class Activity
{
public static function Create(/* your params */)
{
// construct cache and key, whatever
$obj = unserialize($cache->get($key));
if ($obj) return $obj;
return new Activity(/* params */);
}
// rest of your stuff
}
You'll have to serialize only your object's internal state, i.e. its parameters (aka "member variables"). In fact, in this instance, serialize() isn't really what you want to do; rather, you want to store your ActivityClass's data to your cache, not the serialization of the entire object. This gets tricky, though, because as you add new parameters later you need to remember to store these in your cache as well.
Alternatively, you can implement a singleton or factory pattern for your ActivityClass. Since you say you're pulling the class from the cache in the constructor, I take it that only one instance of this class is meant to exist at any given time? In this case, you should make your class a singleton, by doing the following:
Make the __construct() method private or protected.
Create a public static method (I tend to call this getInstance()) that will check your cache for the object, or instantiate a new one and then cache it.
Now instead of directly instantiating a new ActivityClass object, you instead write $foo = ActivityClass::getInstance();, which gives you either a new object or unserializes and returns your cached one.
As you noticed, you cannot just override the current object as a whole.
Instead, a possibility would be to store the data you're serializing/unserializing into a property of your object.
This way, you wouldn't serialize your whole object, but only one of its properties -- and only that single property would be overriden when unserializing.
Typically, you wouldn't serialize the connection to the database, which could be another property of your object.
Another possibility would be to not have your object deal with its own (de-)serialization.
Instead, you should :
Use an external class to instanciate your object
With that external class being responsible of either :
Loading data from cache and pushing it into your object,
Or calling the right method of your class, to load data from the database -- and, then, save that object to cache.
Is there any way I can persist objects in PHP?
I am creating some objects in a script, but I have to create them everytime the script is run (losing their state unless I save it to DB).
I know variables can be persisted with $_SESSION global, but should I save objects in it?
If object persistance is not possible, what's the use of OOP in PHP?
Serialize the object before you store it in the session:
$s_obj = serialize($myObj);
$_SESSION['myObj'] = $s_obj;
and later, to retrieve and reconstruct it:
$s_obj = $_SESSION['myObj'];
$myObj = unserialize($s_obj);
There is no need to serialize objects:
<?php
class A
{
protected $name;
public function __construct($name) { $this->name = $name; }
public function getName() { return $this->name; }
}
session_start();
if (isset($_SESSION['obj'])) {
die( $_SESSION['obj']->getName() );
}
$_SESSION['obj'] = new A('name');
?>
Object persistence is possible, but it is not automatically provided. You either need to write it yourself, or use an object layer that does it for you. So you'll probably need a database.
PHP is not an environment where your program responds to multiple page requests over time: instead, your program is invoked to response to a page request and terminates when it's done.
The purpose of object oriented code in PHP is to make it possible to do a whole raft of programming algorithms and styles, and to make it easier to do an even bigger range of coding solutions. Yes, they are instantiated and destroyed within a single page call, so you have to work within that paradigm. Many codebases pass object IDs around between pages or in sessions; as soon as they need the corresponding object, it is instantiated and loaded from persistent storage using that ID. A good object layer will make this easy.
Agree with jcinacio, no need to serialize values before inserting into $_SESSION..
php will manage serialize/unserialize for you on each page request/end.
Another way to persist objects/sessions is to save them on file/database, "emulating" the php behaviour. In this case you'll need to serialize values to convert them into strings, and unserialize them once retrieved from database to convert them back to object.
You may also be interested in the __sleep and __wakeup "Magic Methods" [0] of the object you're going to save. These methods are called when serializing/unserializing the object, to perform action such as connecting/disconnecting from a database, etc.
[0] http://php.net/oop5.magic
Note that if your state is truly shared between the various users, you don't want to use $_SESSION. $_SESSION is only available in the same user session - i.e. if you have 50 users on the site at once, every one of them will have to pay the computation penalty at least once.
In those cases, you might want to use a persistent disk-based on in-memory (memcache) cache.
Try a cache like APC http://www.php.net/apc/