My website (served by PHP) uses some values, which are expensive to calculate (and the calculation is deterministic), therefore I'd like to cache the result at the first request. Then I could use this function:
function MyValue($valueID) {
if (!isset($myValueCache[$valueID])) {
$myValueCache[$valueID] = ... // The long and expensive calculation.
}
return $myValueCache[$valueID];
}
The question is, how to declare $myValueCache to preserve its value between different calls of the script? I'd call it "server-level static variable" or something like. A simple static variable is not the desired solution. http://www.elated.com/articles/php-variable-scope-all-you-need-to-know/ writes: "Once the script exits, a static variable gets destroyed, just like local and global variables do." I'd like to preserve the value until I explicitly unset it. Thanks :)
PS. "expensive" means database access for example. Calculating and hard-coding the result is not possible at development time.
You should consider using of any in-memory database, like Redis or Memcached. You can also try to cache values in files, but it will be slower than in-memory databases.
Related
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();
I met storage problem with php.
What I want is when each time I visit the function Main of Class A, I can get the value of variable $temp of last time.
P.s. I know I can use session, but it wastes many memory, and not safe.
so I want to find another solution.
Below is the code.
class A {
//initilize the value, how to make it just initialize once?
private static $temp = 0;
public function Main() {
echo "Last time I was=". $this->temp;
$this->temp += 1;
}
}
Thank you for your guys' help! Waiting for your idea
static variable value is stored in a request lifetime.sessions are safe enough to even store authentication data in it so if you want to store this data between multiple requests i recommend sessions or database.
Will it be useful if you store it in a separate file, you overwrite the value in it and read from it when needed?
Is it possible to store an anonymous function in a session var and use it later on?
For instance:
$func = "echo $str;";
$_SESSION['myfunc'] = create_function('$str',$func);
When I call $_SESSION['myfunc']('Hello') it works fine on the page it is created in. When called in another page however, I get the error
Call to undefined function()
The other session-vars are available, so that's not the problem. In the session data I see a reference to a lambda, but I can't get it to work.
You can't store an actual function in a session variable - the variable that you're storing in the session needs to be serializable, and lambdas are not. Plus, this seems like a very convoluted thing to do.
Why not store the name of the function that you want to call, and then execute it that way? Or, if you really want to achieve this, you could store the function string in the session, then create the function after the session is restarted.
However, there's almost certainly a better way of achieving what you want.
There is a library allowing to serialize closures: https://github.com/jeremeamia/super_closure
This might allow you to store a closure in a session.
Not sure it's a good idea, though.
The very reason that you would like to store a function in a session variable means that you're doing something wrong. What is the intention of this strategy from your side?
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.
The question is if a database connection should be passed in by reference or by value?
For me I'm specifically questioning a PHP to MySQL connection, but I think it applies to all databases.
I have heard that in PHP when you pass a variable to a function or object, that it is copied in memory and therefore uses twice as much memory immediately. I have also heard that it's only copied once changes have been made to the value (such as a key being added/removed from an array).
In a database connection, I would think it's being changed within the function as the query could change things like the last insert id or num rows. (I guess this is another question: are things like num rows and insert id stored within the connection or an actual call is made back to the database?)
So, does it matter memory or speed wise if the connection is passed by reference or value? Does it make a difference PHP 4 vs 5?
// $connection is resource
function DoSomething1(&$connection) { ... }
function DoSomething2($connection) { ... }
A PHP resource is a special type that already is a reference in itself. Passing it by value or explicitly by reference won't make a difference (ie, it's still a reference). You can check this for yourself under PHP4:
function get_connection() {
$test = mysql_connect('localhost', 'user', 'password');
mysql_select_db('db');
return $test;
}
$conn1 = get_connection();
$conn2 = get_connection(); // "copied" resource under PHP4
$query = "INSERT INTO test_table (id, field) VALUES ('', 'test')";
mysql_query($query, $conn1);
print mysql_insert_id($conn1)."<br />"; // prints 1
mysql_query($query, $conn2);
print mysql_insert_id($conn2)."<br />"; // prints 2
print mysql_insert_id($conn1); // prints 2, would print 1 if this was not a reference
Call-time pass-by-reference is being depreciated,so I wouldn't use the method first described. Also, generally speaking, resources are passed by reference in PHP 5 by default. So having any references should not be required, and you should never open up more than one database connection unless you really need it.
Personally, I use a singleton-factory class for my database connections, and whenever I need a database reference I just call Factory::database(), that way I don't have to worry about multiple connections or passing/receiving references.
<?php
Class Factory
{
private static $local_db;
/**
* Open new local database connection
*
* #return MySql
*/
public static function localDatabase() {
if (!is_a(self::$local_db, "MySql")) {
self::$local_db = new MySql(false);
self::$local_db->connect(DB_HOST, DB_USER, DB_PASS, DB_DATABASE);
self::$local_db->debugging = DEBUG;
}
return self::$local_db;
}
}
?>
It isn't the speed you should be concerned with, but the memory.
In PHP 4, things like database connections and resultsets should be explicitly passed by reference. In PHP 5, this is done automatically, so you don't have to make it explicit.
BTW, singleton methods for creating database handles are a good idea: you can do $db = & Database::Connection(); and always get the correct handle. This saves you from using a global and the static method can do extra magic (like opening it automatically) for you. Just be careful of when your application scales enough that it needs multiple databases: then your magic function will have to know how to hand you back the correct one. IME this is not hugely difficult; the basic way to solve that is for the code layer that needs the DB handle to know how to ask for the correct one.
A database connection does not actually hold the underlying values, so you don't have to worry about losing assignments made inside a function. Metaphorically, you can think of a DB connection as, say, a runway number -- "OK, DB Connection 12 is cleared to be used for a query" -- The query and result set use the connection, and may need exclusive access for awhile, but the connection does not know anything about the underlying data.
A few people have said that you don't need to worry about this for PHP 5. This is incorrect, if you have a database OBJECT that you're using for all access. In that case, you do need to pass by reference, otherwise it instantiates a new DB object, which (often) creates a new connection to the database.
I discovered this using XDebug & WinCacheGrind, which kindly shows all the destructors that get called - in my case, a halfdozen or more database objects.
To clarify: The reason I point this out is that this is a common way of using Database connections, instead of the raw connection resource.
i don't really have a specific answer for php, but in general it would seem to me that you would want to pass this by reference if you are not explicitly sure that you encounter performance issues when passing by value.
Generally speaking, references are not faster in PHP. It's a common misconception, because they are semantically similar to C pointers, so people familiar with C often assume they work the same way. Not so. In fact, references are a tiny bit slower than copies, unless you actually assign to the variable (Which in any case is bad style, unless the variable is an object).
PHP has a mechanism called copy-on-write, which means that a variable isn't actually copied before it needs to. You can pass a huge data structure to a function; As long as it just reads from it, it makes no difference. A reference however, needs an additional entry in the internal registers, so it would actually take some extra processing (Though barely noticeable).