I have a structure like this:
class My_Class extends Another_Class {
private $my_data = array();
public function append_to_my_data() {
$my_data[] = $this->get_result();
}
}
The append_to_my_data method is called from an AJAX recursion, it is supposed to handle an array by small pieces and combine results by appending them to the $my_data property. But it seems that on each call of this method, the $my_data property is empty again and does not contain the results from the previous call.
Why does it happen? Should I look for another method of storing this data? I would not like to store the data in my JavaScript recursion because it might be quite deep and the data might get quite large.
By AJAX, I assume you mean Javascript.
This tells me one thing, you try to persist data between http requests from your client app (the Javascript code) and your server app code (PHP).
Be aware the JS/client runs on the user's machine in the browser, and the PHP code runs on your own server machine. Two totaly different machines with separate memory/hard disk and CPU.
To persist data on the server between different http requests there are many ways/approaches you can use.
The two MOST common ways are to use php sessions and/or MySQL database, there are many more ways to do it, the two above are the most common ones.
And, to access an object property, you will need to use the $this
i.e.:
$this->my_data[] = $this->get_result();
and not
$my_data[] = $this->get_result();
Related
With the use of static variables and the singleton pattern, I thought that it would be easy enough to create a simple shopping cart that remembered what items where in the cart when another page was loaded.
I am having a problem of the shopping cart not remembering what was already in it when the page is refreshed.
Is there a problem with my code below or should I just use globals or a mysql database.
What is the best way to go about storing state..
<?php
//create a singleton class
class shoppingCart {
private static $_shoppingCartItems = array();
private static $_instance = null;
private function __construct(){
}
public static function getInstance(){
if(self::$_instance == null)
self::$_instance = new shoppingCart();
return self::$_instance;
}
public function add(ShoppingItem $item){
$this->_shoppingCartItems[] = $item;
}
public function cartCount(){
return count($this->_shoppingCartItems);
}
}
?>
Implementation
$item = new shoppingItem();
$shoppingCart = shoppingCart::getInstance();
$shoppingCart->add($item);
$shoppingCart->add($item);
//should increment by 2 on each page load but it doesn't
echo $shoppingCart->cartCount();
Static class members (or any other variables for that matter) are not preserved across different requests. Never.
Sessions to the rescue
The only exception to this is $_SESSION; which is a special mechanism to allow for just that.
Star the session with session_start() at the top of your script.
You can now use $_SESSION like a regular array to store and retrieve information. A session belongs to a single user, it is not a means of sharing data across all your users.
Have a look here for an introduction.
Silence
You must not output anything before session_start() is called. That is to say, <?php must be the exact first thing in a PHP script that wishes to use sessions. Further, there must be no echo statements or any other output generating functions between <?php and session_start().
Output Buffering
If you really must generate output before starting the session, you can use output buffering.
Notes
$_SESSION is forgetful. After a certain time of inactivity on the user's side, the data will be deleted.
If you get the following error message, you violated the above guidelines. Another possibility is that your script has a BOM (Unicode byte order mark). If so, remove it.
Warning: session_start(): Cannot send session cookie - headers already
sent by (output started at
The reason this happens is due to the way PHP handles output: It tries to get the output as fast as possible to the user. However, the HTTP protocol transmits certain control data (cookies, which session belongs to you etc), called "headers" before all the output ("body") of the response. As soon as you output anything, the headers need to get sent - unless you use output buffering that is.
I think I can see your thought pattern there but what you're trying to do is wrong in many ways.
1. Singleton is NOT a pattern, it's an antipattern
The Singleton is an anti-pattern and should be avoided at all costs. See this great answer by Gordon for the why.
2. HTTP is a stateless protocol.
Nothing you do in PHP alone will help you to preserve state across two requests. Your $shoppingCart is created from the scratch for each request, in fact, your whole application is. You should NOT try to persist data in objects instead you should recreate state after every request, by fetching the respective data from somewhere else. In your example probably from some sort of database nosql or sql.
3. Sessions
You can persist user specific data in the superglobal $_SESSION, but in most cases I advice against it. Your user session should hold authentication and user data but you should avoid storing all kinds data relevant for your business logic in there.
PHP is not an application server. It will not automatically persist your "application" state between requests. You have to do that yourself via $_SESSION, cookies, and/or your own private methods.
Unless you take steps to preserve data, the state of the application is wiped when the HTTP request that invoked the script(s) is ended.
I'm working with a PHP MVC Framework. Works really well. I like the separation of the business layer (model) with the business logic (controller). But i just stumbled upon a problem. Here's the thing:
Suppose i navigate to the following url:
http://localhost/user/showall/
In this case the userController.php is called and within that file there is a method showallAction() which gets executed.
In the showallAction() method i simply do a request to a model which gets all the users for me. Something like this:
public function showallAction()
{
// create userModel object
$users = new userModel();
// get all users and assign the data to a variable which can be accessed in the view
$this->view->users = $users->getAllUsers();
// render views
$this->view->render();
}
So this method gets all the users, assigns the data returned from the userModel to a variable and i can easily work with the returned data in my view. Just a typical MVC thing.
Now here comes the problem.
I also need to create a native iphone variant. Ofcourse the looks will be totally different. So all i actually want to do is to request this url:
http://localhost/user/showall/
And that it just gives me the array (in json format) back. So i can use that for the mobile development.
But this obviously can't be done right now because the showallAction() method assumes that it is for web browser display. It doesn't echo JSON formatted, instead it simply assings the array of users to a variable.
So that means i have to create another method "showallMobileAction()" in order to get the data, but specifically for the mobile device. But this is not an elegant solution. I'm sure that are better ways...
Anyone any idea how can i solve this problem??
In your situation i would modify the routing mechanism.
It would be useful, if you could add extension at the end of URL, which represents the format you expect, like :
http://foo.bar/news/latest >> HTML document
http://foo.bar/news/latest.html >> HTML document
http://foo.bar/news/latest.rss >> you RSS feed
http://foo.bar/news/latest.json >> data in JSON format
It's a simple pattern to recognize. And you can later expand this to add .. dunno .. pdf output, or Atom feeds.
Additionally , two comments :
Model is not a type of objects. Instead it is a layer, containing objects responsible for business logic, and objects responsible for data storage/retrieval.
View should be a full blown object, to which you bind the domain objects (objects responsible for business logic).
You could pass parameters to your url:
/user/showall/json
and get the third URL segment with a custom function or a built-in one. For instance, with CodeIgniter: $this->uri->segment(3).
Some frameworks will pass the additional parameters to your method. Just try this with the URL I wrote above:
public function showallAction()
{
print_r(func_get_args());
}
I'm not familiar with PHP MVC but in general terms I'd use the "accepts" HTML header field to request the response in either "text/html" or "text/json", the controller would check for the accepts type and return the response accordingly.
So, I don't come from a huge PHP background—and I was wondering if in well formed code, one should use the 'superglobals' directly, e.g. in the middle of some function say $_SESSION['x'] = 'y'; or if, like I'd normally do with variables, it's better to send them as arguments that can be used from there, e.g:
class Doer {
private $sess;
public function __construct(&$sess) {
$this->sess =& $sess;
}
}
$doer = new Doer($_SESSION);
and then use the Doer->sess version from within Doer and such. (The advantage of this method is that it makes clear that Doer uses $_SESSION.)
What's the accepted PHP design approach for this problem?
I do like to wrap $_SESSION, $_POST, $_GET, and $_COOKIE into OOP structures.
I use this method to centralize code that handles sanitation and validation, all of the necessary isset () checks, nonces, setcookie parameters, etc. It also allows client code to be more readable (and gives me the illusion that it's more maintainable).
It may be difficult to enforce use of this kind of structure, especially if there are multiple coders. With $_GET, $_POST, and $_COOKIE (I believe), your initialization code can copy the data, then destroy the superglobal. Maybe a clever destructor could make this possible with $_SESSION (wipe $_SESSION on load, write it back in the destructor), though I haven't tried.
I don't usually use any of these enforcement techniques, though. After getting used to it, seeing $_SESSION in code outside the session class just looks strange, and I mostly work solo.
EDIT
Here's some sample client code, in case it helps somebody. I'm sure looking at any of the major frameworks would give you better ideas...
$post = Post::load ();
$post->numeric ('member_age');
$post->email ('member_email');
$post->match ('/regex/','member_field');
$post->required ('member_first_name','member_email');
$post->inSet ('member_status',array('unemployed','retired','part-time','full-time'));
$post->money ('member_salary');
$post->register ('member_last_name'); // no specific requirements, but we want access
if ($post->isValid())
{
// do good stuff
$firstName = $post->member_first_name;
}
else
{
// do error stuff
}
Post and its friends all derive from a base class that implements the core validation code, adding their own specific functionality like form tokens, session cookie configuration, whatever.
Internally, the class holds a collection of valid data that's extracted from $_POST as the validation methods are called, then returns them as properties using a magic __get method. Failed fields can't be accessed this way. My validation methods (except required) don't fail on empty fields, and many of them use func_get_args to allow them to operate on multiple fields at once. Some of the methods (like money) automatically translate the data into custom value types.
In the error case, I have a way to transform the data into a format that can be saved in the session and used to pre-populate the form and highlight errors after redirecting to the original form.
One way to improve on this would be to store the validation info in a Form class that's used to render the form and power client-side validation, as well as cleaning the data after submission.
Modifying the contents of the superglobals is considered poor practice. While there's nothing really wrong with it, especially if the code is 100% under your control, it can lead to unexpected side effects, especially when you consider mixed-source code. For instance, if you do something like this:
$_POST['someval'] = mysql_real_escape_string($_POST['someval']);
you might expect that everywhere PHP makes that 'someval' available would also get changed, but this is not the case. The copy in $_REQUEST['someval'] will be unchanged and still the original "unsafe" version. This could lead to an unintentional injection vulnerability if you do all your escaping on $_POST, but a later library uses $_REQUEST and assumes it's been escaped already.
As such, even if you can modify them, it's best to treat the superglobals as read-only. If you have to mess with the values, maintain your own parallel copies and do whatever wrappers/access methods required to maintain that copy.
I know this question is old but I'd like to add an answer.
mario's classes to handle the inputs is awesome.
I much prefer wrapping the superglobals in some way. It can make your code MUCH easier to read and lead to better maintainability.
For example, there is some code at my current job the I hate! The session variables are used so heavily that you can't realistically change the implementation without drastically affecting the whole site.
For example,
Let's say you created a Session class specific to your application.
class Session
{
//some nice code
}
You could write something like the following
$session = new Session();
if( $session->isLoggedIn() )
{
//do some stuff
}
As opposed to this
if( $_SESSION['logged'] == true )
{
//do some stuff
}
This seems a little trivial but it's a big deal to me. Say that sometime in the future I decide that I want to change the name of the index from 'logged' to 'loggedIn'.
I now have to go to every place in the app that the session variable is used to change this. Or, I can leave it and find someway to maintain both variables.
Or what if I want to check that that user is an admin user and is logged in? I might end up checking two different variables in the session for this. But, instead I could encapsulate it into one method and shorten my code.
This helps other programmers looking at your code because it becomes easier to read and they don't have to 'think' about it as much when they look at the code. They can go to the method and see that there is only ONE way to have a logged in user. It helps you too because if you wanted to make the 'logged' in check more complex you only have to go to one place to change it instead of trying to do global finds with your IDE and trying to change it that way.
Again, this is a trivial example but depending on how you use the session this route of using methods and classes to protect access could make your life much easier to live.
I would not recommend at all passing superglobal by reference. In your class, it's unclear that what you are modifying is a session variable. Also, keep in mind that $_SESSION is available everywhere outside your class. It's so wrong from a object oriented point of view to be able to modify a variable inside a class from outside that class by modifying a variable that is not related to the class. Having public attribute is consider to be a bad practice, this is even worst.
I found my way here while researching for my new PHP framework.
Validating input is REALLY important. But still, I do often find myself falling back to code like this:
function get( $key, $default=FALSE ){
return (isset($_GET[$key]) ? $_GET[$key]:$default);
}
function post( $key, $default=FALSE ){
return (isset($_POST[$key]) ? $_POST[$key]:$default);
}
function session( $key, $default=FALSE ){
return (isset($_SESSION[$key]) ? $_SESSION[$key]:$default);
}
Which I then use like this:
$page = get('p', 'start');
$first_name = post('first_name');
$last_name = post('last_name');
$age = post('age', -1);
I have found that since I have wildly different requirements for validation for different projects, any class to handle all cases would have to be incredibly large and complex. So instead I write validation code with vanilla PHP.
This is not good use of PHP.
get $_SESSION variables directly:
$id = $_SESSION['id'];
$hash = $_SESSION['hash'];
etc.
I have a flash application which uses a single php file to retrieve records from a database (using the Zend framework). When the application first begins, I make a call to the php to set a class variable, so that all future requests to the database will use this variable to select records based on its value. So here is how the class begins:
class MyClass
{
private $animal = "";
public function setAnimal($anim) {
$this->animal = $anim;
echo($this->animal); //this correctly prints the variable I passed in
}
Later, based on user input, I make a call to a different method in this class, but it's as if the class variable $animal has been forgotten, because it no longer has a value on any subsequent accessing of the class:
public function getAnimals()
{
echo('getAnimals: ');
echo($this->animal); //this prints nothing - as if it doesn't know what "animal" is
$result = mysql_query("SELECT * FROM animals WHERE animal='$this->animal'"); //and therefore this query doesn't work
$t = array();
while($row = mysql_fetch_assoc($result))
{
array_push($t, $row);
}
return $t;
}
So my question is, how can I get a PHP class variable to persist so that I can set it once, and I can access it anytime during the life of an application?
I could be mis-interpreting your question, but it sounds like you first make a call to a PHP script from your Flash, and later you are making a second call to the PHP script from the Flash and expecting a certain variable to be set?
If this is the case, then it is also the problem. PHP is stateless. Every time you access a PHP script (ie, request the URL), the PHP environment is re-created from scratch. As soon as the request is done and the PHP script is finished executing, the environment is destroyed (ie. the web server thread shuts down, and the PHP environment is lost). Anything you set or do in your first request won't exist on your second request.
If you want information to persist, you can use sessions or cookies. Since you're using Flash, sessions is probably the best way to go. The first time you call your script, generate a session token and pass it back to the flash with your response. On all subsequent calls, your Flash should provide the session token, and you can store/fetch any state variables you need from $_SESSION.
I have instantiated a class in my index.php file. But then I use jQuery Ajax to call some PHP files, but they can't use my object that I created in the index.php file.
How can I make it work? Because I don´t want to create new objects, because the one I created holds all the property values I want to use.
Use the session to save the object for the next page load.
// Create a new object
$object = new stdClass();
$object->value = 'something';
$object->other_value = 'something else';
// Start the session
session_start();
// Save the object in the user's session
$_SESSION['object'] = $object;
Then in the next page that loads from AJAX
// Start the session saved from last time
session_start();
// Get the object out
$object = $_SESSION['object'];
// Prints "something"
print $object->value;
By using the PHP sessions you can save data across many pages for a certain user. For example, maybe each user has a shopping cart object that contains a list of items they want to buy. Since you are storing that data in THAT USERS session only - each user can have their own shopping cart object that is saved on each page!
Another option if you dont want to use sessions is to serialize your object and send it through a $_POST value in your AJAX call. Not the most elegant way to do it, but a good alternative if you don't want to use sessions.
See Object Serialization in the documentation for more informations.
mm, you should store in session, $_SESSION["someobj"] = $myobj;, and ensure that when you call the Ajax PHP file this includes the class necessary files which defines the class of $myobj and any contained object in it.
Could you be more specific? I can try.
This is how I create an object then assign it to a session variable:
include(whateverfilethathastheclassorincludeit.php)
$theObject = new TheObjectClass();
//do something with the object or not
$_SESSION['myobject'] = $theObject;
This is how I access the object's members in my Ajax call PHP file:
include(whateverfilethathastheclassorincludeit.php)
$theObject = $_SESSION['myobject'];
//do something with the object
If you don't want to move your object that is in your index.php, have your ajax make a request to index.php but add some extra parameters (post/get) that let your index.php know to process it as an ajax request and not return your normal web page html output.
You have not provided code, but what I guess is that you need to make your instantiated object global for other scripts to see it, example:
$myobject = new myobject();
Now I want to use this object elsewhere, probably under some function or class, or any place where it is not getting recognized, so I will make this global with the global keyword and it will be available there as well:
global $myobject;
Once you have the object, you can put it into the session and then utilize it in the Ajax script file.
As others have suggested, $_SESSION is the standard way to do it, in fact, that was one of the reasons, that sessions where invented to solve. Other options, i.e. serializing the object rely on the client side to hold the object and then return it untampered. Depending on the data in the object, it is not a good solution, as a) the object may include information that should not be available on the client side for security reasons and b) you will have to verify the object after receiving it.
That said, and if you still want to use the object on the client side, then JSON is an option for serializing object data, see JSON functions in PHP.
Based on most of the answers here, referring to storing the object in $_SESSION, is it more efficient to store only the individual properties that need to be accessed in AJAX as opposed to the whole object, or does it not matter?
E.g.
$_SESSION['object'] = $object;
vs
$_SESSION['property1'] = $object->property1;
$_SESSION['property2'] = $object->property2;
I know the OP is asking about accessing the entire object, but I guess my question pertains to if it's just a matter of only accessing certain properties of an object, and not needing to access methods of a class to alter the object once it's in AJAX.