SitePoint Sponsor

User Tag List

Page 2 of 3 FirstFirst 123 LastLast
Results 26 to 50 of 54
  1. #26
    SitePoint Evangelist galt's Avatar
    Join Date
    Apr 2002
    Posts
    461
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally posted by voostind
    - The code that reads/writes the superglobals is concentrated in one place. There is only
    one object that processes the results of a form being posted. When some other part of the
    application needs those same results, it must request them from previously mentioned
    object, which it can only do if that object is in scope.
    I am having trouble envisioning how a system would be written to use a single object for all global variables. DO you mean you just build a class like this? (example)
    PHP Code:
    class oscalls {
       function 
    get_request_uri(){
          return 
    $REQUEST_URI;
       }

    I never thought about it, but I guess that really does give a layer of independence from the o/s. This layering stuff is hard to think thru on my own. I wish I could get a class or a good book on it. I guess that is why I am here..

  2. #27
    SitePoint Evangelist
    Join Date
    Oct 2001
    Posts
    592
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I am having trouble envisioning how a system would be written to use a single object for all global variables. DO you mean you just build a class like this? (example)
    It's not quite like this. Let me try to elaborate a little.

    Imagine your code generates a HTML-page with multiple forms on it. This is not that uncommon; many portals have polls, subscription boxes, message boxes and so on, all on a single page. If all forms are posted to the same page, they typically have a common field, describing which form that is (e.g. '<input type="hidden" name="source" value="poll">'). Now, one way to handle a post is doing something like this:

    PHP Code:
    if (isset($_POST) && isset($_POST['source']))
    {
      switch(
    $_POST['source']))
      {
        case 
    'poll':
          
    // big chunk of code here
          
    break;
        case 
    'subscribe':
          
    // big chunk of code here
          
    break;
        case 
    'message':
          
    // big chunk of code here
          
    break;
      }

    Although I see this kind of code quite often (possible in the disguise of an 'if ... elseif .... elseif ...'-statement), it's not so good a solution. Why not?
    - If the 'big chunks of code' get large (and they often do), the code becomes unreadable.
    - Only one such chunk is actually executed; the others are just there doing nothing but taking time for the PHP interpreter to skip them anyway.
    - If additional forms are added, the switch-statement needs to change as well, getting even bigger.
    - If the forms on the page are dynamic, in that it isn't known in advance precisely which statements are on the page and which aren't, the 'switch'- or 'if'-statement doesn't quite 'fit'.

    If you use OOP - and most regulars here by now know I do nothing else - you can replace the above piece of code in a straightforward way, resulting in code that's easier to read and faster to execute. Say that for every possible form, there is a class derived from a common baseclass called FormHandler. The class that handles the poll is called PollFormHandler, and the class that handles the subscription is called SubscribeFormHandler. And so on. Every form handler has a method 'execute' (which is thus declared in class FormHandler) that checks the posted variables for validity and handles the post. The switch-statement above can now be implemented as follows:

    PHP Code:
    if (isset($_POST) && isset($_POST['source']))
    {
      
    $class ucfirst($_POST['name']);
      
    $file "${class}FormHandler.php";
      if (
    file_exists($file))
      {
        include_once(
    $file);
        
    $handler = new $class();
        
    $handler->execute();
      }

    This transformation is called 'Replacing conditional with polymorphism' in the book 'Refactoring' by Martin Fowler. It has the following advantages:
    - It's easy to read, and equally easy to understand
    - Only the code that actually gets executed is inserted into the system
    - Adding a new form to the page is simple; just write a small handler class (e.g. FooMessageHandler for a form with source="foo"), and the above code works instantly
    - The code is very suitable for pages
    that generate an unknown set of forms.

    Another result of this transformation is that the $_POST array is no longer accessed in one place: every handler does that on its own. This seems to contradict my earlier statements on the use of the superglobals. But this is not really true:
    - I still have one entry point for reading $_POST for some specific form in my system. Class PollFormHandler will only handle the variables posted by the polling form, and it won't handle any other (like the ones posted by the subscription form).
    - Depending on the implementation of class FormHandler, I can encapsulate all references to $_POST, so that subclasses needn't refer to it. For example:

    PHP Code:
    class FormHandler
    {
      var 
    $vars;

      function 
    FormHandler()
      {
        
    $this->vars $this->getVariables();
      }

      function 
    execute()
      {
        if (
    $this->check())
        {
          
    $this->handle($_POST);
        }
      }

      function 
    check()
      {
        foreach (
    $this->vars as $var)
        {
          if (!isset(
    $_POST['var']) || !this->checkVariable($var$_POST['var'])) {
            return 
    false;
        }
        return 
    true;
      }

      function 
    checkVariable($name, &$value)
      {
        
    // To be overridden by subclasses
        
    return true;
      }

      function 
    handle($form)
      {
        
    // To be overridden by subclasses
      
    }

      function 
    getVariables()
      {
        
    // To be overridden by subclasses
        
    return array();
      }
    }

    class 
    PollFormHandler extends FormHandler
    {
      function 
    checkVariable($name, &$var)
      {
        switch (
    $name)
        {
          case 
    'subject'// A DB ID value
            
    $var = (int)$var;
            return 
    true;
          case 
    'opinion'// A number between 0 and 5
            
    $var = (int)$var;
            return 
    $var >=&& $var <= 5;
        }
        return 
    false;
      }
      function 
    handle(&$form)
      {
        
    // Insert the poll-results into the database
        // subject_id = $form['subject'];
        // opinion    = $form['opinion'];
      
    }

      function 
    getVariables()
      {
        return array(
    'subject''opinion');
      }

    In the code above, class FormHandler takes care of accessing $_POST, and no subclass needs to do that itself. (Note: this is simplified example code; it might not even work right away.)

    Another thing that happens a lot is that GET- or POST-variables are read in various independent parts of the system. Consider an application where users can specify how many query results they want to show on a single page. One part of the code computes and executes the query, using the user-specified value. Another part of the code shows a navigation bar (first-, prev-, next- and last-buttons), and reads that same value. By making these pieces of code read the exact same value (e.g. $_GET['page_size']), they get too close a connection to one another. By creating a single entry point to the specified value (e.g. in an object), both pieces of code can be re-used much better.

    Vincent

  3. #28
    SitePoint Guru
    Join Date
    Oct 2001
    Posts
    656
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I have found a *very, very* interesting site about Design Patterns, ways to build a layered system. I recommend it to any PHP (or any other language) programmer who wants to learn some good programming theory.

    The site is actually a draft for a book written by this guy, Martin Fowler:

    http://www.martinfowler.com/isa/index.html

  4. #29
    SitePoint Evangelist
    Join Date
    Oct 2001
    Posts
    592
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    A good link indeed!

    By the way, I often use the term 'Refactoring' in my posts on this forum. That Martin Fowler fellow wrote the book on it. So there you go :-)

    Vincent

  5. #30
    SitePoint Guru
    Join Date
    Oct 2001
    Posts
    656
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I have been reading various pages at Martin Fowler's site and I find them very interesting. After reading them (like 10 times already in total, I think ) I read some posts about the subject on this forum and I found Fowler's name in on of your posts, voostind.

  6. #31
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Any time I need to use the database connection (that was made in init), I just global $DB, and use local instances of Query.
    Which is completely and utterly stupid

  7. #32
    SitePoint Enthusiast Sasa's Avatar
    Join Date
    Mar 2003
    Location
    Cologne, Germany
    Posts
    60
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Great! Vincent in back on track. Seems like you have some free time on your hands again, which is great cause it just makes reading this forum fun again.

    Now I have to go and change my code and kill all those convenience globals that gave me so much comfort. I always wondered why I didn't get clean layers in my framework. Here we go ...
    Sasa

  8. #33
    SitePoint Addict
    Join Date
    Aug 2002
    Location
    Ottawa, Ontario, Canada
    Posts
    214
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Heh, that post by Vincent was May of 2002

    Cheers,
    Keith.

  9. #34
    SitePoint Enthusiast Sasa's Avatar
    Join Date
    Mar 2003
    Location
    Cologne, Germany
    Posts
    60
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Ahh, it went up on the updated threads in my notification hm, wonder when he will be back though ...
    Sasa

  10. #35
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Heh, that post by Vincent was May of 2002
    I updated the thread with a comment I made which I think was an important issue to address, thus bring this excellent thread back into the spotlight.

  11. #36
    SitePoint Wizard guelphdad's Avatar
    Join Date
    Oct 2003
    Location
    St. Catharines, ON Canada
    Posts
    1,706
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Maelstrom

    you might want to check out ACCU (Association of C/C++ Users) website, they have reviews on over 3,000 books on C/C++. I recently took a beginners course on C and was looking around for another book on C++. I found the reviews quite helpful.
    http://www.accu.org/

  12. #37
    SitePoint Wizard Mike Borozdin's Avatar
    Join Date
    Oct 2002
    Location
    Edinburgh, UK
    Posts
    1,743
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by voostind
    It's me again, that guy that never stops whining about global variables... :-)



    It's exactly the opposite: when using global variables, you LOSE the layers. When you think you have a system of, say, 6 layers, and you put the database object $DB in the first and use it in the sixth (as 'global $DB', that sixth layer becomes, by definition, the second layer: in an n-layered system, layer n directly depends on layer n-1, but not on any layer lower than n-1. That's the whole point of layering. When your sixth layer becomes in effect the second layer, the third, fourth and fifth layers no longer exist. And gone is your layered code. Thank you global variables!

    On the other hand: how many layers does a typical PHP application have? That depends on how you code it, of course, but most of the code I get to see (in forums and such) has at most two. In that case you can argue that using global variables isn't that bad, because there are no layers to mess up anyway... My answer to that: if an application use only 2 layers, it has a bad design.

    Let's examine the typical PHP code for printing a list of articles (or books, or whatever):
    PHP Code:
    function printList($category_id)
    {
    global 
    $DB;
    $DB->query("select id, name from article where category = $category_id);
    while (
    $row $DB->fetchRow())
    {
    print 
    "<a href=""\"article.php?id=${row['id']}\">${row['name']}</a><br>\n";


    Code like this is very common. Although a very short function, it does many things:
    - It executes an SQL query
    - It traverses all rows in a query result
    - It prints each row in some way

    When you think about this for a while, you'll see that there are forced dependencies in this code that needn't be there. You can see these dependencies by looking at the code in 'reverse order':
    - Information on a single article is printed. Where does this information come from? It currently comes from a set of rows, and there's no way to change that.
    - A set of rows is traversed. Where do these rows come from? They currently come from an executed query, and so it will be forever.
    - A query is executed on a database connection. Where does that connection come from? It is currently imported in the function by using 'global', making this function directly dependent on the layer the database object was declared in.

    I'm not saying this is all wrong, or that it should be any different. For the sake of the argument, I'm only using a very simple example. Anyway, it's clear that this code, although doing much, has only one layer. And that has its consequences. What if the articles should be printed differently, or the query must be changed, or a different database connection should be used, or a whole different datasource (a flat file)? The only way to change those things now is by updating ALL of the code. Because it's all in the same layer. (Note again: it's a very simple example, hopefully you get the idea.)

    Another way of implementing the above example is like this:
    PHP Code:
    function selectList(&$database$category_id)
    {
    return 
    $database->execute("select id, name from article where category = $category_id);
    }

    function 
    printList(&$it)
    {
    for (
    $it->reset(); $it->isValid(); $it->next())
    {
    $row = &$it->getCurrent();
    print 
    "<a href=""\"article.php?id=${row['id']}\">${row['name']}</a><br>\n";
    }
    }

    $result selectList($database12);
    $iterator = new QueryIterator($result);
    printList($iterator);

    // Or, more compact:
    printList(new QueryIterator(selectList($database12))); 
    An explanation is in order: the method 'execute' of class Database returns an object of class QueryResult, which can be used to access rows in the result. These methods are not part of the Database class (like before in '$DB->fetchRow()), because I want to be able to run another query while I'm still processing the first. By separating the database connection from the query result this is suddenly possible (and the code gets simpler as well). To process the rows I could either access each row through the interface of class QueryResult (e.g. '$row = $result->getRow(3)'), but in this case I wrap it up in an 'iterator', which is passed along to the function 'printList'. I also have iterators for built-in arrays and strings, lines in files, nodes in XML trees... All iterators have the same interface, so function 'printList' has become a generic function (it works on any datastructure I have an iterator for) instead of a specialized one.

    Looking at the functions calls in the pipeline, you'll see that they are printed in the same order as the dependencies (or: reversed from what they were at first): show results -> get list -> select data. That's not just a coincidence!

    Even though this is a very simple example, hopefully you'll notice the following:
    - Function 'selectList' knows about the database connection.
    - The QueryIterator knows nothing about the database connection, only about the result from some query.
    - Function 'printList' knows nothing about the database connection or the fact that the data it processes comes from an executed query.

    If I have code like this, and I use a global variable in function 'printList', the nice layering I got is immediately destroyed. And that's definitely not what I aimed for when I designed and coded it this way! Maybe in this particular case it's not much of a problem. But in a larger application, with many layers, it certainly is.

    There are many other remarks I could make about this example (why this is so much better ;-)), but this is not the place (nor the time; it's getting late here). The subject was 'global variables'. Once again. <<Sigh>> I'll say it one more time, and I will probably have to repeat this 'til my dying day: "global variables are evil!"

    Vincent
    Ok! But what about the Singleton pattern. You can try to make an instance of your DB class and if it exists, the instanciating function will return it.

  13. #38
    SitePoint Member
    Join Date
    Oct 2003
    Location
    Ukraine
    Posts
    19
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Can't understand, what are you discussing for?

    Very simple way is to create class, that redefines globals, and make one array that contains all our global.
    Aditionally, creating main program class will solve all problems. As an example:

    index.php
    PHP Code:
    <?php

    define 
    TOP        ,    './'            ,    true );
    define INC        ,    './inc/'        ,    true );

    class 
    CNK
    {
        
        var 
    $input    = Array();
        var 
    $base_url  "";
        ..........
        var 
    $conf         "";
        
        Function 
    CNK() 
        { 
            global 
    $VARS$STD, ... , $DB$CONF;

            
    $this->vars        = &$VARS;
            
    $this->std        = &$STD;
            ......
            
    $this->db            = &$DB;        
            
    $this->conf             = &$CONF;
        }
    }

    require ( 
    INC  'vars.class' $CONF['PHP_EXT']);
    $VARS = new Vars();

    require ( 
    INC  'func.class' $CONF['PHP_EXT']);
    $STD = new Std();

    .............

    require ( 
    DB  'db.class' $CONF['PHP_EXT']);
    $DB = new DB();

    require ( 
    TOP  'conf' $CONF['PHP_EXT']);

    $cnk = new CNK();

    ?>
    other_file.php
    PHP Code:
    <?php

    Function SelectSomethingFromDatabase()
    {
        global 
    $cnk;  // our global class

        
    $cnk->db->query("__OUR__SQL__QUERY__");
        while ( 
    $res $cnk->db->fetch_row() )
        {
            
    /// some action :)
            
    $cnk->std->replace_string$res['field'], "second param" );
            
    /// ... and so on
        
    }
    }

    ?>
    All needed globals in one object I always use this construction and it always works fine.

  14. #39
    SitePoint Zealot
    Join Date
    Aug 2003
    Location
    Brisbane, QLD
    Posts
    101
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    isn't this the sort of thing aspect oriented programming is supposed to help with?

    * disclaimer, i know next to nothing about AOP

  15. #40
    SitePoint Member
    Join Date
    Oct 2003
    Location
    Ukraine
    Posts
    19
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    isn't this the sort of thing aspect oriented programming is supposed to help with?

    * disclaimer, i know next to nothing about AOP
    Joking?

  16. #41
    ********* Victim lastcraft's Avatar
    Join Date
    Apr 2003
    Location
    London
    Posts
    2,423
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    Hi...

    Quote Originally Posted by soapsud
    isn't this the sort of thing aspect oriented programming is supposed to help with?

    * disclaimer, i know next to nothing about AOP
    I am kind of hoping to write an AOP tool for PHP after SimpleTest.

    You are basically attaching decorators/proxies invisibly to classes through a separate central language. The language is Cool in AspectJ and XML in Nanning.

    A simple example might be a permission aspect. Create an aspect (proxie) that looks the class name and method up against the user's role. if the method is not permitted then pass an error, else run the method and return the result. You then wrap that proxy around the classes you want to protect. Those classes are used in exactly the same way (same name), but the proxies can be plugged and unplugged without the application code noticing. It means that the main code is not cluttered with permission checks which tend to cut accross the class hierarchy and mess things up a bit.

    yours, Marcus
    Marcus Baker
    Testing: SimpleTest, Cgreen, Fakemail
    Other: Phemto dependency injector
    Books: PHP in Action, 97 things

  17. #42
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Any chance that you have some sample script ?

  18. #43
    ********* Victim lastcraft's Avatar
    Join Date
    Apr 2003
    Location
    London
    Posts
    2,423
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    Hi.

    Only if you lend me your time machine. Sending me back a year should just about do it .

    yours, Marcus
    Marcus Baker
    Testing: SimpleTest, Cgreen, Fakemail
    Other: Phemto dependency injector
    Books: PHP in Action, 97 things

  19. #44
    SitePoint Zealot
    Join Date
    Aug 2003
    Location
    Brisbane, QLD
    Posts
    101
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    deal! you go first

  20. #45
    SitePoint Evangelist ghurtado's Avatar
    Join Date
    Sep 2003
    Location
    Wixom, Michigan
    Posts
    591
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Marcus, I am interested in understanding your approach to AOP a little bit better, as it sort of resonates with something that has been roaming my thoughts for the last few months. Ideally, I would like to find a way to "plug" and "unplug" aspects of my application at will and without hassle, to facilitate debugging during development and for a million other purposes. One way this would become tremendously useful is for an instance to disable all authentication in your app while you are debugging it, same for form validation... etc.

    Please do expand on your comment a little more!

  21. #46
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Following on from Lastcrafts last post and your requirement to plug and unplug functionality then I'd suggest that the Decorator Pattern would be a good choice;

    I use it at the moment for my DOM Widget's classes Seams to work okay so far I might add...

  22. #47
    ********* Victim lastcraft's Avatar
    Join Date
    Apr 2003
    Location
    London
    Posts
    2,423
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    Hi...

    Quote Originally Posted by ghurtado
    Ideally, I would like to find a way to "plug" and "unplug" aspects of my application at will and without hassle, to facilitate debugging during development and for a million other purposes. One way this would become tremendously useful is for an instance to disable all authentication in your app while you are debugging it, same for form validation...
    As I hinted earlier, I haven't built any kind of tool yet . In fact I am still trying to find time to play with the Java tools and other stuff is eating up my time right now.

    As for unit testing of permissions we usually have an Access object that gets passed into objects that need to request things. Testing involves passing in a mock object version of that Access class instead. The rquirements of testing tend to push us in the direction of a highly factored design and this is a good example of this. You can do everything that AOP can by passing things around, it just gets more cluttered.

    We have a lot of unit tests because they are much easier than system tests. For system testing we have a fake database. We can create a test wrapper for our other systems as follows...
    PHP Code:
    $registry = &Registry::instance();
    $connection = &new MysqlConnection(..., 'test');
    $registry->setEntry('db'$connection);

    include(
    $_GET['target']); 
    By adding the target parameter to this script as the name of the script under test, we can get it to execute this code snippet first. It basically sticks a connection to the test database into the registry before the real system can get to it and create a live connection. The application code sees there is already a connection and doesn't create another. This means that we can add special users to the test database as part of a test and not affect the real data.

    Anyway, that is our current way of coping with it.

    yours, Marcus
    Marcus Baker
    Testing: SimpleTest, Cgreen, Fakemail
    Other: Phemto dependency injector
    Books: PHP in Action, 97 things

  23. #48
    SitePoint Evangelist ghurtado's Avatar
    Join Date
    Sep 2003
    Location
    Wixom, Michigan
    Posts
    591
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Marcus, after your reference to Aspect Oriented Programming in PHP, my curiosity was piqued and I went out to learn how it is being implemented in Java. It looks very interesting, the whole concept about cross sections and aspect checkpoints. It sounds like something like that could do a LOT of good for otherwise well designed PHP applications out there.

    What are everyone's thoughts on the matter? How do you think this could be implemented in PHP? (without an inconvenient C++ add on, or some other limiting implementation). I am interested to see how this can be attained using the standard PHP syntax, or something very close to it.

    I think further discussion about the topic is likely to throw some good ideas into the mix, and perhaps this is something that some of us would like to start working on.

    Anyway, just dreaming for a while

  24. #49
    ********* Victim lastcraft's Avatar
    Join Date
    Apr 2003
    Location
    London
    Posts
    2,423
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    Hi...

    I definitely want to give it a go some time in the future. It comes down to attaching the behaviour via the overload() function. If the aspect language (probably XML) generates a bunch of overload() functions (via XSLT say) that just attach Aspect classes to the intercepts, then it should all be possible. I haven't looked at it very deeply yet.

    yours, Marcus
    Marcus Baker
    Testing: SimpleTest, Cgreen, Fakemail
    Other: Phemto dependency injector
    Books: PHP in Action, 97 things

  25. #50
    SitePoint Evangelist ghurtado's Avatar
    Join Date
    Sep 2003
    Location
    Wixom, Michigan
    Posts
    591
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Interesting approach. If I understood it right, this would work by using the overloading extension as a means to "decorate" the base classes with custom "aspects" during runtime. Does anyone have any good tutorials / resources on how to use the overload() function as a Decorator pattern?

    This is interesting but it leaves me wanting to see more complete uses of overload().


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •