I'm looking for a way to prevent repeated calls to the database if the item in question has already been loaded previously. The reason is that we have a lot of different areas that show popular items, latest releases, top rated etc. and sometimes it happens that one item appears in multiple lists on the same page.
I wonder if it's possible to save the object instance in a static array associated with the class and then check if the data is actually in there yet, but then how do I point the new instance to the existing one?
Here's a draft of my idea:
$baseball = new Item($idOfTheBaseballItem);
$baseballAgain = new Item($idOfTheBaseballItem);
class Item
{
static $arrItems = array();
function __construct($id) {
if(in_array($id, self::arrItems)){
// Point this instance to the object in self::arrItems[$id]
// But how?
}
else {
// Call the database
self::arrItems[id] = $this;
}
}
}
If you have any other ideas or you just think I'm totally nuts, let me know.
You should know that static variables only exist in the page they were created, meaning 2 users that load the same page and get served the same script still exist as 2 different memory spaces.
You should consider caching results, take a look at code igniter database caching
What you are trying to achieve is similar to a singleton factory
$baseball = getItem($idOfTheBaseballItem);
$baseballAgain =getItem($idOfTheBaseballItem);
function getItem($id){
static $items=array();
if(!isset($items[$id])$items[$id]=new Item($id);
return $items[$id];
}
class Item{
// this stays the same
}
P.S. Also take a look at memcache. A very simple way to remove database load is to create a /cache/ directory and save database results there for a few minutes or until you deem the data old (this can be done in a number of ways, but most approaches are time based)
You can't directly replace "this" in constructor. Instead, prepare a static function like "getById($id)" that returns object from list.
And as stated above: this will work only per page load.
Related
I'm working on a project that requires a lot of separate objects (classes) to work in unison. I've come up with a solution to my problem, but I just wanted to hear some other perspectives, because I feel like i'm missing something.
So essentially, I have a visitor and a location class, each are initialized and are stored within a variable, such as $visitor and $location; both having data unique to the visitor and location referenced on the page call.
What I want/need to do is essentially make a 'bridge' so I can call a method that will affect both of these objects. For instance, I want to be able to call $bridge->favorite(); and it will both add that favorite reference to the visitor's profile in addition to increasing the number of favorites the location has.
What I have done right now is essentially made a bridge:
$bridge = new Bridge($locationclass, $visitorclass);
$bridge->favorite();
So it essentially calls another class I have, 'bridge,' with the method favorite, then would use the two classes already set. Which I think is an okay solution, but I feel like i'm missing a better solution.
All input would be extremely helpful, thank you for your time!
If you need to do this kind of stuff, it means that your application is not well designed.
To answer your example, what you have to do is adding the location to the visitor's favorite places, only.
And if you want to count how many times were a location added to favorites, count how many visitors have it in their favorites. Don't store two times the same information.
class Bridge{
private $classes;
function construct($classes)
{
$this->classes = $classes;
}
function _call($name,$params)
{
foreach($classes as $class)
{
if(method_exists($class,$name)){
return call_user_method_array($name,$class,$params);
}
}else{
...
}
}
I have a CI page that will load to a div in view file, using jQuery. Using switch(page_parameter), I control what is showing from the page.
When I call the page for 3rd time, I set a value to the class array.
But when I call the 4th time, the array become empty.
I was wondering, is it actually possible to use the class property to store value that can be used after page re-access? Or something missing in my head?
I know that using session is not a good idea, since the real array is a big chunk of serialized xml.
Here's my code:
class MyClass extends MY_Controller
{
public static $pitems = array();
function Hotel(){
parent::MY_Controller();
}
function new_campaign(){
$params = $this->uri->uri_to_assoc();
switch($params['step']){
case '3' : self::$pitems = array("test","another"); //here the class array was set successfully
$this->load->view('viewer');
break;
case '4' : print_r(self::$pitems); //here the array is empty
break;
}
}
In the viewer page, there's a call to the page:
Next page
Same issue also with $this->
What am i missing here?
Thanks in advance~
edit:
I saw a script that has similar scenario. it successfully reused the variable set in the constructor, instead of treating it as a class variable. i'll look thorough to confirm this, but for now, i'll close this thread. Thanks Chris for sharing.
Im not really sure what your trying to do but I have users jQuery post()/get()/ajax() many of times in CI and have had no problems. So despite not knowing or understanding what your trying to do. I thought I'd at least say I know loading data without refresh in CI through something like jQuery isn't an issue. Example on system I built on CI had a twitter like feed of tweets where jQuery on a timer was polling for new data and coming back with it each time accordingly if something new was to be shown.
I'm using this code in a views field template (in this case views-view-field--all-members--uid.tpl.php):
<?php
$users_friends = flag_friend_get_friends($user->uid);
$users_friends_ids = array();
foreach ($users_friends as $id => $value) {
$users_friends_ids[] = $id;
}
?>
It basically gets the user ids of friends and puts them in an array so I can check if the field matches any of the user ids.
So my problem is that I don't want to have this within this template (for a few reasons), but if I don't I can't access the array. How can I make this array globally accessible?
Without knowing your "few reasons", I can't say if this is the answer for sure. My own reasons would probably be that I don't want the same code executing a bunch of times, and I'd rather not have the same exact code in multiple places.
I would then create a function with a static variable to hold the friends array.
function mymodule_get_friends_ids() {
// pull in the current global user variable
global $user;
// call up the static variable
static $users_friends_ids;
// return if this static var has already been set
if (is_array($users_friends_ids)) {
return $users_friends_ids;
}
// if we hit here, then this function has not been
// run yet for this page load.
// init array
$users_friends_ids = array();
// if user is anon, no need to go on
if (user_is_anonymous()) {
return $users_friends_ids;
}
// get friends array
$users_friends = flag_friend_get_friends($user->uid);
// build ids array
foreach ($users_friends as $id => $value) {
$users_friends_ids[] = $id;
}
return $users_friends_ids;
}
Now in your templates, you can call mymodule_get_friends_ids() in as many places as you want, and the working code below the first return will only get executed the first time it is called.
Coder1's advice is very good - it keeps you from populating your global variable namespace with a lot of junk. It's probably the most "elegant." It might not be the easiest to use if you are rather new to PHP (which I'm guessing might be the case if it's hard to get your head around returning arrays, but that's ok).
However, if this is really a priority, you probably don't care about having one extra global variable.
I suppose I may be stating the obvious here - but you can, at pretty much any point in execution (provided the information you need has already been generated - e.g., the $user variable has been populated), do this:
$GLOBALS['users_friends_ids'] = /* your code goes here */
Then in your template, you access this by ...
$friendsArray = $GLOBALS['users_friends_ids'];
Or you can simply use the construct
global $user_friends_ids;
when you want to initialize the variable, or access it inside a function or class (which is the case for your template files - they are called inside functions, so you need to globalize or use the $GLOBALS array, which is "automagically" all of the variables active in the global namespace).
The most "logical" place to do this would be inside a module using one of the many hooks available, to execute this code only once. hook_init() might do it for you, if the user object is already loaded at this point (not sure, you'll have to test). But you might not want to figure out making Drupal modules (it's not that difficult).
If you are doing this inside a template (and though it's not good practice, many Drupal site owners with a beginning knowledge of PHP put everything in templates), you'll want to know which template code is being executed when. Node template code tends to be executed before page template code - which is logical, since otherwise the variables for node content in the page template wouldn't be populated.
If you have listings of nodes, they'll be calling this code multiple times, so you'll end up doing something similar to what Coder1 is describing. If you don't want to create your own small module, you could put the function declaration he's written in your theme's template.php file, since it's called only once. You don't want to put function declarations in the tpl.php files, since they are sometimes called more than once (and you aren't allowed to declare functions more than once).
If you have a hard time understanding the function and the return, you can always do something like this in your code (which is very, very inelegant - but it's better to have inelegant code that you do understand, than elegant code that's you don't).
if(!isset($GLOBALS['users_friends_ids'])) {
$GLOBALS['users_friends_ids'] = /* your code here */
}
I'm looking for the "best practice" way to achieve a message / notification system. I'm using an OOP-based approach for the script and would like to do something along the lines of this:
if(!$something)
$messages->add('Something doesn\'t exist!');
The add() method in the messages class looks somewhat like this:
class messages {
public function add($new) {
$messages = $THIS_IS_WHAT_IM_LOOKING_FOR; //array
$messages[] = $new;
$THIS_IS_WHAT_IM_LOOKING_FOR = $messages;
}
}
In the end, there is a method in which reads out $messages and returns every message as nicely formatted HTML.
So the questions is - what type of variable should I be using for $THIS_IS_WHAT_IM_LOOKING_FOR?
I don't want to make this use the database. Querying the db every time just for some messages that occur at runtime and disappear after 5 seconds just seems like overkill.
Using global constants for this is apparently worst practice, since constants are not meant to be variables that change over time. I don't even know if it would work.
I don't want to always pass in and return the existing $messages array through the method every time I want to add a new message.
I even tried using a session var for this, but that is obviously not suited for this purpose at all (it will always be 1 pageload too late).
Any suggestions?
Thanks!
EDIT: Added after I caused some confusion with the above...
The $messages array should be global: I need to be able to add to it through various different classes as well as at the top-level of the whole script.
The best comparison that comes to mind is to use a database to store all the messages that occur at runtime, and when it's output-time, query the database and output every message. The exception to this comparison is just that the lifetime of the $messages array is the page load (they accumulate during page load, and vanish right after).
So, for example, say I have 10 different actions running one after the other in the script. Each one of these actions make use of a different class. Each one of these classes should be able to post to $messages->add(). After all 10 actions have run, it's "output time", and the $messages array can contain up to 10 different messages which were added via all the different classes.
I hope this clarifies it a bit.
I'm not exactly clear about what you want to do, but a good way would be to simply use a private variable:
class messages {
private $messages = array();
public function add($new) {
$this->messages[] = $new;
}
public function output() {
// Whatever; e.g. a foreach loop that echoes all the messages
}
}
I think you need either a instance field.
In PHP I know many people will use a class to SET and GET session variables, I am doing this now in many classes, I need to know if I am doing it wrong though.
So for example lets pretend I have A class that need to use this
$session->get('user_id')
Which gets this value
$_SESSION['user_id']
Now in this class if I have 15 methods and in each method I need to access this value several time, currently I am calling $session->get('user_id') 20 times in a class if it is needed 20 times, should I be setting this 1 time per class to a local variable for that class and then access it? I am not sure if it makes any difference or not, my theory is that the way I am doing it now is 20 extra function calls that could be avoided?
If my theory is correct, what would be the best way to store these values inside a class? Like a private or public or protected variable?
Thanks, sorry for any confusio, classes and objects are taking me a while to learn.
Also note that $session->get('user_id') is just 1 of many DIFFERENT variables I would need to do the same thing to as well.
UPDATE
After reading Chacha102's post about using an array() ... here is what I have tried, does this look like a good way or still can be improved a lot?
class file
<?PHP
class User
{
// Load user details into an Array
public function load_user()
{
$this->user_id = $this->session->get('user_id');
//if user ID is already set, then Load the cached urser data
if(isset($this->user_id) && $this->user_id != ''){
// set user data to an array
$this->user['user_id'] = $this->user_id;
$this->user['user_name'] = $this->session->get('user_name');
$this->user['pic_small'] = $this->session->get('pic_small');
$this->user['sex'] = $this->session->get('sex');
$this->user['user_role'] = $this->session->get('user_role');
$this->user['location_lat'] = $this->session->get('location_lat');
$this->user['location_long'] = $this->session->get('location_long');
$this->user['new_user'] = $this->session->get('new_user');
return $this->user;
}
}
}
?>
main page file
<?PHP
require 'user.class.php';
$user = new User;
// if a user_id is set into a session variable then we return an array of other user related data
$user->account = $user->load_user();
// would show the user's ID from our array
echo $user->account['user_id'];
?>
If you are doing something like this:
if($session->get('user_id')==1)
{
$prefs = get_prefs($session->get('user_id'));
$info = get_info($session->get('user_id'));
}
then I would replace it with a since local variable
$id = $session->get('user_id');
if($id == 1)
{
//.....
}
It increases clarity for one. It probably isn't a big deal to call a simple function like that over and over again, but I still wouldn't do it.
I try to reduce the number of functions I call in a single method. If you are doing something like:
$user_id = $session->get('user_id');
$name = $session->get('name');
// ... etc ...
You might just want to grab an array of all the session variables instead.
$user = $session->get_array();
echo $user['user_id'];
This reduces the function calls, and you get all the data in one fell swoop.
Just one thing on clarity, using an array of user data is probably easier to read than to create a variable for each thing ($user_name, $user_id, etc).
For accesses distributed over a number of methods, as long as you're just using the function to access the variable, I'd say stay with the function. The additional cost is minuscule, and it's better for long term maintainability.
Within the same method, you would make one function call, populating a local variable, as Chacha102 suggests.
Even if the function does resource-intensive things like database calls, I would prefer giving the function some internal caching before adding a member to your class.
Adding the variable as a member to your class doesn't really make sense in the OOP way, because it's not a logical, legitimate member of the class but just a temporary variable.