3

I've got a class I wrote to work with the front end (web browser side) of a shopping cart.

It's fairly simple in that I send the class a product ID that I bury in the URL and then query a database populating the classes variables for use in retrieving the data through some public methods.

To interface with my actual physical web page I have a file I call viewFunctions.php. Wherein I instantiate my class called ItemViewPackage():

<?php
require_once(dirname(__FILE__) . '/ItemViewPackage.php');
$viewObject = new ItemViewPackage($_GET['page']);

So, I have shoppingcartpage.php (the physical url) that requires the file viewFunctions.php that loads my class ItemViewPackage().

The output page shoppingcartpage.php calls functions like get_item_info('title') or get_item_info('price') which in the viewFunctions.php file is made like so:

function get_info($type){
    echo $viewObject->get_info($type);
}

Now, right off the bat, this isn't working because, I assume, $viewObject is not global. So I make $viewObject global like so:

function get_info($type){
    global $viewObject;
    echo $viewObject->get_info($type);
} 

But, this doesn't work either, I still get an error for "Call to a member function get_info() on a non-object"

Now, the only thing that works is:

function get_info($type){
    $viewObject = new ItemViewPackage($_GET['page']);
    echo $viewObject->get_info($type);
}

But, I don't want to re-instantiate my object every time I make a call to this function (which is several times for several bits of information). I'd rather instantiate once at the top of my viewFunctions.php doc and use that object every time I call this function.

Am I going about this completely wrong?

Thanks in advance. DIAGRAM (hopefully it helps visualize)

Diagram

enter image description here

Howard Zoopaloopa
  • 3,798
  • 14
  • 48
  • 87
  • It's not entirely clear what you're asking. Are you expecting the `$viewObject` instance to persist across multiple executions of your script? – kqnr Apr 14 '11 at 05:02
  • It's multiple executions of a function, not the script. I assume. – Howard Zoopaloopa Apr 14 '11 at 05:11
  • 1
    You probably *do not* want a singleton. I have to ask, why isn't `get_info` a method of the `ItemViewPackage` class, rather than a free floating function that operates on a global? – kqnr Apr 14 '11 at 05:24
  • @chomp, I'm trying to minimize my database queries. I'm hoping with one instantiation of the object I can use the data already in memory rather than going back and forth with the database every time I look for a bit of information. Also, some info returned will be working upon other functions and having them all in one class feels tidier. – Howard Zoopaloopa Apr 14 '11 at 05:28

4 Answers4

3

What for do you need viewFunctions.php anyway? It's only wrapping the ItemViewPackage. Remove that and use the ItemViewPackage directly, e.g.

// shopping.php
include_once 'ItemViewPackage.php';
$viewObject = new ItemViewPackage($_GET['page']);
<div><?php echo $viewObject->get_info('title'); ?></div>
<div><?php echo $viewObject->get_info('price'); ?></div>

Then you dont have to bother with globals or Singletons. If you dont want a second instance, dont instantiate a second one. It's simple as that in PHP. If there is anything in viewFunctions.php that modifies the output of the $viewObject instance, consider making that into a class and have it aggregate the $viewObject into a property, e.g.

// viewFunctions.php
include_once 'ItemViewPackage.php';
$viewObject = new ItemViewPackage($_GET['page']);
$helper = new ViewObjectHelper($viewObject);

then you can access the $viewObject from within the Helper object with $this->propertyName.

As for reducing load to the database: this is a solved problem. Consider using a cache.

Community
  • 1
  • 1
Gordon
  • 312,688
  • 75
  • 539
  • 559
  • @gordon. The reason I'm trying to leave my "shopping.php" free of any superfluous code. I have my index.php page parse the url and load the correct "template" (which in this case is shopping.php) and load another file called viewFunctions.php that houses a list of functions I'd like available FOR my template. As far as I'm concerned it's an issue of organization. – Howard Zoopaloopa Apr 14 '11 at 14:47
  • @Jascha if you are accessing the ItemViewPackage anyways with the viewFunctions, then I dont see how using them directly is superfluous code or helping organization. You are adding a superfluous layer with those viewFunctions. But anyway, go with my second suggestion and remake the functions into a HelperObject and inject the ItemViewPackage instance into the helper instance. Or use Caching. – Gordon Apr 14 '11 at 14:50
  • @gordon, I say it's superfluous because I may or not be loading shopping.php but will ALWAYS be loading viewFunctions.php. So, I'd like any and all of my class objects/functions to be available from any "template" page by housing all of my includes in one file-viewFunctions.php. My classes and viewFunctions.php will always live in the same directory. My template file could be named anything so if I'm including from viewFunctions.php it's as simple as writing require_once('viewFunctions.php') rather than finding out where I am with shopping.php (../../admin/modules/inventory/classes/etc...) – Howard Zoopaloopa Apr 14 '11 at 15:02
  • @Jascha i'm not sure that approach sounds sane to me, but in any case, I still say make the functions into an helper object and inject `ItemViewHelper`. – Gordon Apr 14 '11 at 15:17
  • @gordon. I don't see how that isn't totally sane. I'm ALWAYS going to be loading viewFunctions.php so I want to instantiate my $viewObject there. What could possibly be wrong with that? – Howard Zoopaloopa Apr 14 '11 at 15:40
  • @Jascha well, I dont see why you would want to have **all** your classes and functions available in viewfunctions. Nor do I see what the location of files has to do with that since you are hopefully using an autoloader to handle that for you. Anyways, without knowing the details of your architecture it's rather pointless argueing about that aspect. If you want to talk about that, consider coming to the chat. To answer your question for the fourth time now: Make the functions into an Helper Object. Inject the `ItemViewPackage` instance. – Gordon Apr 14 '11 at 16:03
  • @gordon, I appreciate your input, I really do. But I'm still at a loss WHY my function does not work. I'm looking into the helper object now. But, I still don't see any problem with building my own function interface for use with my templates other than it seems objects don't want to act as global variables. – Howard Zoopaloopa Apr 14 '11 at 16:40
  • @Jascha actually, the code with `global` should work as long as `$viewObject` is defined in the global scope. You can check the `$GLOBALS` array to see if it's in there. But you definitely do not want to use any globals as this will introduce coupling and as an "OOP enthusiast" you want to be [SOLID](https://secure.wikimedia.org/wikipedia/en/wiki/Solid_(object-oriented_design)) and avoid coupling because it hurts testability and maintainability. – Gordon Apr 14 '11 at 16:50
  • @gordon, My assumption is that it does have to do with my architecture. I am pulling shopping.php THROUGH a function, therefore any variables or objects OUTSIDE the scope of that function will not be available... does that sound right? – Howard Zoopaloopa Apr 14 '11 at 16:57
  • 1
    @Jascha absolutely. [From docs](http://de.php.net/manual/en/function.include.php): *When a file is included, the code it contains inherits the variable scope of the line on which the include occurs. Any variables available at that line in the calling file will be available within the called file, from that point forward. However, all functions and classes defined in the included file have the global scope.* – Gordon Apr 14 '11 at 17:07
2

You want the singleton pattern, please see this answer:

Creating the Singleton design pattern in PHP5

This allows you to get an instance of your class in any scope, and it will also be the same instance.

Community
  • 1
  • 1
therealjeffg
  • 5,790
  • 1
  • 23
  • 24
  • We use a singleton pattern a lot in order to limit instances of objects that have persistent connections to other network services, eg databases or caches. It's pretty useful because it limits the number of connections open. – therealjeffg Apr 16 '11 at 18:17
1

What scope is the $viewObject created in?

Note: that even though it appears to be in the global scope because it is not in a function within the shown file, if the file is included from within a function it will be in that scope...

i.e.


file1.php

include 'file2.php';

function includefile($file) {
    include $file;
}

includefile('file3.php');

file2.php

$global = 'this is global';

file3.php

$notglobal = 'this is not';
Jacob
  • 8,278
  • 1
  • 23
  • 29
-1
<?php
require_once(dirname(__FILE__) . '/ItemViewPackage.php');

$viewObject = new ItemViewPackage($_GET['page']);

function get_info($type){
    global $viewObject;

    echo $viewObject->get_info($type);
}

This should work from viewFunctions.php and any file that includes it such as shopping.php. So from shopping.php we can do either:

echo get_info($type);

or

echo $viewObject->get_info($type)

This alone raises some logical flags in my head. Not sure why you want to wrap the object again.

daganh
  • 421
  • 2
  • 5
  • This does NOT work. This is why I'm posting the question in the first place. – Howard Zoopaloopa Apr 14 '11 at 15:03
  • I tested by adding 3 files per your diagram and was mearly confirming this should work if you have it setup like your diagram. Then you added another diagram with index.php that would suggest your not following the previous layout diagram. I'm just confirming your first use case should work if laid out the way you described. – daganh Apr 14 '11 at 21:23