SitePoint Sponsor

User Tag List

Page 2 of 4 FirstFirst 1234 LastLast
Results 26 to 50 of 76
  1. #26
    morphine for a wooden leg randem's Avatar
    Join Date
    Jun 2002
    Location
    .chicago.il.us
    Posts
    957
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    In fairness to Harry, I wanted to provide some code to show that I'm not just a critical bystander.
    PHP Code:
    <?php
    class EventMarshall
    {
        
    //Constructor
        
    function EventMarshall()
        {
            if(
    $_GET)  $this->trigger_get();
            if(
    $_POST$this->trigger_post();
            
            if(
    $_SERVER['PATH_INFO']) $this->trigger_path_info();
            
            
    // default page trigger
            
    if(function_exists('main')){
                
    main( &$this );
            }
        }
        function 
    trigger_get()
        {
            
    // GET trigger
            
    if(function_exists('on_get_value')){
                
    reset($_GET);
                while(list(
    $key,$value)=each($_GET)){
                    
    on_get_value( &$this$key$value );
                }
            }
            if(
    function_exists('on_get')){
                
    on_get(&$this$_GET);
            }
        }
        function 
    trigger_post()
        {
            
    // POST trigger
            
    if(function_exists('on_post_value')){
                
    reset($_POST);
                while(list(
    $key,$value)=each($_POST)){
                    
    on_post_value(&$this$key$value);
                }
            }
            if(
    function_exists('on_post')){
                
    on_post(&$this$_POST);
            }
        }
        function 
    trigger_path_info()
        {
            
    // PATH_INFO trigger
            
    $data explode('/'$_SERVER['PATH_INFO']);
            if(
    function_exists('on_path_data')){
                for(
    $i=0;$i<count($data);$i++){
                    if(
    $data[$i])
                        
    on_path_data(&$this$data[$i]);
                }
            }
        }
    }
    new 
    EventMarshall();
    ?>
    which could be implemented in the following manner...
    PHP Code:
    <?php

    require_once 'EventMarshall';

    function 
    on_path_data$sender$value ){
        switch(
    $value){
            case 
    'foo':
                print 
    '<b>foo</b> command issued.<br/>';
                break;
            default:
                
    printf('unrecognized command "%s" issued.<br/>'$value);
                break;
        }
    }
    function 
    on_get_value$sender$key$value ){
        
    printf('<b>%s</b> = %s<br/>'$key$value);
    }
    function 
    main$sender ){
        print 
    'hello world.<br/>';
    }

    ?>
    Last edited by randem; Oct 23, 2002 at 12:50.
    ----Adopt-a-Sig----
    Your message here!

  2. #27
    As the name suggests... trickie's Avatar
    Join Date
    Jul 2002
    Location
    Melbourne, Australia
    Posts
    678
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    randem i like how you have extended pippo's idea so that if you make a POST request and pass GET variables they can still trigger events.

    bit i think that the code posted just delay's the fusebox approach to 'events' even further...

    I mean you still have to have a big switch statement or parse what is requested and then do something.

    I think that it is a good idea to be able to call:
    [PHP
    $request->getParam("param")
    [/PHP]

    and for that parameter to be returned whether it is a GET or POST request, but i like Harry's idea that you can register a param or event with a handler and that handler can automatically be called.

    I think that if you have one generic handler like:
    PHP Code:
       function on_get_value$sender$key$value ){
         
    //parse $key then call specific handler for event.
       

    then you are just delaying the same action that would occur if you ran everything by the fusebox/index.php?action=blah approach.


    ---edit----

    And i know i don't offer any code... but i will when i finish my current uni assignment. Honest!!

  3. #28
    No. Phil.Roberts's Avatar
    Join Date
    May 2001
    Location
    Nottingham, UK
    Posts
    1,142
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Its possible to extend the idea of a http-request handler even further. For instance, a base class containing basic POST/GET/etc array handlers, and extension classes to handle query-string parsing and cookie handling. This way you could have a single application for standard query param oparsing, and one that could also interpret "search engine friendly" parsing.

    Heres a basic CGI class I made not long ago, I'll work on expanding it in the above fasion after work..

    PHP Code:
    <?php
    //
    // +----------------------------------------------------------------------+
    // | CGI                                  |
    // +----------------------------------------------------------------------+
    // | Copyright (c) Phil Roberts                      |
    // +--------------------------------------------------------------------
    // | Authors: Phil Roberts <phil@heropr.com>                |
    // +----------------------------------------------------------------------+
    //
    // $Id: CGI.php,v 1.0 28/09/2002
    //

    class CGI
    {
      
    // {{{ properties

      /**
      * Stores the query parameter array.
      * @var     array
      * @access  private
      */
      
    var $_param;

      
    /***
      * Stores the ampersand-parsing parameter.
      * @var    bool
      * @access private
      ***/
      
    var $_use_ampersands;

      
    /**
      * Default constructor
      */
      
    function CGI()
      {
        
    // Sets the default value for $this->use_ampersands

        
    $this->use_ampersands(1);
        
        if( 
    strtolower($GLOBALS['REQUEST_METHOD']) == 'post' )
        {
          while( list(
    $k,$v) = each($GLOBALS['HTTP_POST_VARS']) )
          {
            
    $this->_param$k ] = urldecode($v);
          }
        }
        else
        {
          if( 
    $this->_use_ampersands == )
          {
            while( list(
    $k,$v) = each($GLOBALS['HTTP_GET_VARS']) )
            {
              
    $this->_param$k ] = urldecode$v );
            }
          }
          else
          {
            
    $this->parse_params($GLOBALS['QUERY_STRING']);
          }
        }
      }

      
    /**
      * Returns the value of the parameter key $var.
      *
      * @return string
      * @access public
      */
      
    function param($var)
      {
        return 
    $this->_param$var ];
      }

      
    /**
      * Parses a query string to an array.
      * This enables mixed use of both & and; as query
      * string delimeters.
      *
      * @return array
      * @access private
      */
      
    function parse_params($tosplit)
      {
        
    $pairs preg_split('/[&;]/'$tosplit);

        foreach( 
    $pairs as $_ )
        {
          list(
    $k,$v) = explode('='$_);

          
    $value = isset($value) ? $value '';

          
    $param urldecode($k);
          
    $value urldecode($v);

          
    $this->_param$param ] = $value;
        }
      }

      
    /**
      * Returns an associative array of all query values.
      *
      * @return array
      * @access public
      */
      
    function all_parameters()
      {
        return 
    $this->_param;
      }
      
      function 
    use_ampersands()
      {
        
    $this->_use_ampersands 1
      }
    }

    ?>
    THE INSTRUCTIONS BELOW ARE OLD AND MAY BE INACCURATE.
    THIS INSTALL METHOD IS NOT RECOMMENDED, IT MAY RUN
    OVER YOUR DOG. <-- MediaWiki installation guide

  4. #29
    FreeBSD The Power to Serve silver trophy pippo's Avatar
    Join Date
    Jul 2001
    Location
    Italy
    Posts
    4,514
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi,
    talking about _REQUEST usage:

    From manual:
    An associative array consisting of the contents of $_GET, $_POST, $_COOKIE, and $_FILES.
    http://www.php.net/manual/en/reserve...iables.request


    from a bug report:
    The 'voting' on php-dev was in favour for removing the $_FILES from
    $_REQUEST..as it doesn't make much sense
    to have them there. Just FYI.
    http://bugs.php.net/bug.php?id=19848


    I thought interesting give this feedback.



    pippo
    Mr Andrea
    Former Hosting Team Advisor
    Former Advisor of '03

  5. #30
    No. Phil.Roberts's Avatar
    Join Date
    May 2001
    Location
    Nottingham, UK
    Posts
    1,142
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Okay, heres what Ive come up with for my own HTTP Request handler library. It handles both & and ; delimeted query-strings and parses 'search-engine friendly' style url'l as well as handling cookies.

    Its by no means a finished work, but I was curious as to what you all thought of it.

    Here is the base class, HTTP_Request:

    PHP Code:
    <?php

    class HTTP_Request
    {
        var 
    $param;
        var 
    $raw_query;
        var 
    $cookie_vars;
        var 
    $query_string;

        function 
    HTTP_Request()
        {
        }

        function 
    parse_requests()
        {
            if( 
    is_array($GLOBALS['_GET']) )
            {
                while( list(
    $gk,$gv) = each($GLOBALS['_GET']) )
                {
                    if( 
    is_array($gk) )
                    {
                        while( list(
    $ngk,$ngv) = each($GLOBALS['_GET'][$gk]) )
                        {
                            
    $this->raw_query[$gk][$ngk] = $ngv;
                        }
                    }
                    else
                    {
                        
    $this->raw_query[$gk] = $gv;
                    }
                }
            }

            if( 
    is_array($GLOBALS['_POST']) )
            {
                while( list(
    $pk,$pv) = each($GLOBALS['_POST']) )
                {
                    if( 
    is_array($pk) )
                    {
                        while( list(
    $npk,$npv) = each($GLOBALS['_POST'][$pk]) )
                        {
                            
    $this->raw_query[$pk][$npk] = $npv;
                        }
                    }
                    else
                    {
                        
    $this->raw_query[$pk] = $pv;
                    }
                }
            }

            if(
    is_array($_COOKIE))
            {
                while( list(
    $ck,$cv) = each($_COOKIE) )
                {
                    if(
    is_array($ck))
                    {
                        while( list(
    $nck,$ncv) = each($_COOKIE[$ck]) )
                        {
                            
    $this->cookie_vars[$ck][$nck] = $ncv;
                        }
                    }
                    else
                    {
                        
    $this->cookie_vars[$ck] = $cv;
                    }
                }
            }

            if(isset(
    $_SERVER['QUERY_STRING']))
            {
                
    $this->query_string $_SERVER['QUERY_STRING'];
            }
        }

        function 
    get_Requests()
        {
            return 
    $this->raw_param;
        }

        function 
    get_Cookies()
        {
            return 
    $this->cookie_vars;
        }

        function 
    set_Cookie($name,$value=''$expire='',$path='',$domain='',$secure='')
        {
            
    $expire $expire == "" "" time()+3600;

            return 
    setcookie($name,$value,$expire,$path,$domain,$secure);
        }

        function 
    param($pval)
        {
            die(
    'Feature not implemented.');
        }

        function 
    dump_Params()
        {
            die(
    'Feature not implemented.');
        }
    }

    ?>

    The query-string parser class:

    PHP Code:
    <?php

    if(!defined('CLASS_ROOT'))
    {
        
    define('CLASS_ROOT''');
    }

    include_once 
    CLASS_ROOT."HTTP_Request.php";

    class 
    QS_HTTP_Request extends HTTP_Request
    {
        var 
    $use_ampersands;

        function 
    QS_HTTP_Request($use_amp 'false' )
        {
            
    $this->use_ampersands $use_amp;

            
    $this->parse_requests();

            if(
    is_array($this->raw_query))
            {
                if( 
    $this->use_ampersands == 'false' )
                {
                    while( list(
    $k,$v) = each($this->raw_query) )
                    {
                        
    $this->param$k ] = urldecode($v);
                    }
                }
                else
                {
                    
    $this->parse_params($this->query_string);
                }
            }
        }

        function 
    param($pval)
        {
            return 
    $this->param[$pval];
        }

        function 
    dump_Params()
        {
            return 
    $this->param;
        }

        function 
    parse_params($tosplit)
        {
            
    $pairs preg_split'/[&;]/'$tosplit );

            foreach( 
    $pairs as $vars )
            {
                list(
    $k,$v) = explode'='$vars );

                
    $value = isset($value) ? $value '';

                
    $param urldecode($k);
                
    $value urldecode($v);

                
    $this->param$param ] = $value;
            }
        }
    }

    ?>
    And the search-engine friendly url parser class:

    PHP Code:
    <?php

    if(!defined('CLASS_ROOT'))
    {
        
    define('CLASS_ROOT''');
    }

    include_once 
    CLASS_ROOT."HTTP_Request.php";

    class 
    SEF_HTTP_Request extends HTTP_Request
    {
        var 
    $temp_vars;

        function 
    SEF_HTTP_Request()
        {
            
    $this->parse_requests();

            
    $this->temp_vars explode'/',$_SERVER["PATH_INFO"] );

            
    array_shift($this->temp_vars);
            
    reset($this->temp_vars);

            while( list(
    $v,$k) = each($this->temp_vars) )
            {
                list(
    $index,$val) = each($this->temp_vars);
                
    $val urldecode($val);
                
    $this->param[$k] = $val;
                $
    $k $val;
            }
        }

        function 
    param($pval)
        {
            return 
    $this->param[$pval];
        }

        function 
    dump_Params()
        {
            return 
    $this->param;
        }
    }

    ?>
    Attached Files Attached Files
    THE INSTRUCTIONS BELOW ARE OLD AND MAY BE INACCURATE.
    THIS INSTALL METHOD IS NOT RECOMMENDED, IT MAY RUN
    OVER YOUR DOG. <-- MediaWiki installation guide

  6. #31
    As the name suggests... trickie's Avatar
    Join Date
    Jul 2002
    Location
    Melbourne, Australia
    Posts
    678
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    The thing i like most about Harry's code is that he uses the abstract concept of events.

    a CGI or Servlet-like mechinism is very similar in the internals, but the way that Harry has structured the registering of events makes it very easy to abstract the workings of an application.

    Say you want to sit down and try to design an application, then the first part you want to do is identify any patterns that can be used and and design an abstract application architecture. You don't want specifics such as particular request types or variables... you want to identify the events or requests as a whole and defer the implementation specifics.


    Being able to parse any sort of application request is terrific, but the application is not going to implemented the best unless you are able to define the process it does in abstract terms. The use of events could be a terrific way to do that.

    You also don't want to tie an event to a specific set of protocols such as HTTP requests. What if, in the future requests are made via XML-RPC?

    XML-RPC might use HTTP or it might not, and you might want to later integrate your application with a J2EE application or .NET application.

    If you can keep the event registering/triggering abstract enough then when new ways of doing things or different platforms are integrated, then you'll save yourself a hell of of alot of re-coding or messing work arounds.

  7. #32
    SitePoint Guru
    Join Date
    Oct 2001
    Posts
    656
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    The idea of event handling / registering is very interesting and if its done properly, I think a lot of people would be interested in using it (count me in ).

    To keep things as abstract as possible, I think you need a couple of layers for event handling. This is just what I could come up with right now, it's in no way complete.

    • Event Receiving
      Can receive events from HTTP GET, POST, possibly REQUEST_URI (using something like /news/archives/2002/10), XML-RPC, through the command line possibly. You could implement subclasses of an abstract base class for these. This class would give an event to the layer below it:
    • Event Dispatching
      These would look up events in some kind of registry and load the appropriate Event Handler class to further handle the event.

      PHP scripts are compiled and loaded everytime a request is made, and this of course takes processing time. Therefore I think it would be a good idea to dynamically load the Event Handlers. So the registry would also need a file name to include() for the event.
    • Event Handling
      Subclasses of an abstract subclass or something that handle events. Theoretically of course, it shouldn't matter if the event comes via GET, POST, XML-RPC or whatever. However I think the way the event is handled usually depends on the way it is received
    • Domain / Business Logic
      In a correctly layered system (I'm following http://www.martinfowler.com/isa ), the Events (or Commands as Fowler calls them, I think) shouldn't do the actual work themselves but should delegate it to the Domain layer.


    That's just my 2 cents Looking forward to feedback

  8. #33
    SitePoint Evangelist
    Join Date
    Oct 2001
    Posts
    592
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I have been following this thread with interest, and now that the discussion has seemed to have skidded to a halt, I'd like to post some of my observations here. Please correct me if I'm wrong.

    Harry started this thread about event handling because he didn't like the idea of writing long and complicated switch-statements in a single PHP-script to handle all possible events. This, I completely agree with; I don't like them either.

    The solution to Harry's problem is - as it seems now - a couple of classes that can handle the registering and execution of various events. With these classes, a programmer can define a number of events for some page, after which the code connected to the events will take care of handling them. Bye bye switch-statement.... Or not?

    In theory, the switch-statement is still there. But instead of using long and boring conditionals, the idea is as follows:
    - Build a table of possible execution paths, indexed on a simple name (the event)
    - Find out which event was triggered
    - Lookup the selected event in the table
    - Execute the code specified in the table for that event

    This is a sound solution, because it separates the algorithm (event selection) from the task at hand (executing events). This allows the first to be reused and parametrized for other problems.

    In short, I think this sums up what has been discussed in this thread.

    Now, I have a serious problem with the code presented in this discussion. Simply put, I think there's too much of it. Don't get me wrong, I don't disagree with Martin Fowler at all (I wouldn't dare ), but I do think a much simpler implementation is possible, and more importantly, needed. How do you explain to a procedural programmer that he shouldn't write a large and complex switch-statement to handle events, but should instead use about 4 or 5 classes instead? These classes alone are at least twice as big as the whole switch-statement (which, in the end, implements the exact same functionality)!

    All in all, the code in this thread made me think a bit of the template engine discussion we had earlier. Indirection after indirection is introduced, but in the end each indirection - a solution to a partial problem - has little effect on the problem as a whole. The result is that we end up with a large pipeline of code blocks executed one after another, each doing very little.

    So what can we do about it? I think that by going back to the problem we're actually trying to solve we can come up with a much simpler solution that could convince a procedural programmer to use OO. A solution that is implemented with little code, is easy to use and read, and introduces little overhead.

    Instead of using a complex switch-statement, we're going to use an event table. A client calls 'index.php?page=home', and we translate this request by looking up 'home' in the event table that generates pages. As such, the input-side of the problem is pretty simple: it's just a string. The output-side is a bit harder: code specific for some event needs to be executed. By using OOP, this can easily be solved: implement a baseclass (e.g. 'Event') with a single method ('execute'). Each event is then a subclass of this class, executing specific code. An event table can thus be implemented as a single array:

    PHP Code:
    $events = array(
        
    'home'     => new StaticPage('html/home.html'),
        
    'news'     => new NewsPage('news/*.html'),
        
    'feedback' => new StaticPage('html/feedback.html')
    );

    $event =& $events[$_GET['page']];
    $event->execute(); 
    And presto, there's your event handling system, in just three statements...

    Of course, there is a serious problem with this solution. The event table is populated with objects (class instances), of which only one is actually used. Thus, there's a lot of overhead.

    To solve that problem, we can use the Factory Method design pattern. Instead of instantiating an event object, we describe how an event should be created, after which we let a factory create an object for us based on this description:

    PHP Code:
    $events = array(
        
    'home'     => array('class' => 'StaticPage''parameters' => 'html/home.html'),
        
    'news'     => array('class' => 'NewsPage'  'parameters' => 'news/*.html'),
        
    'feedback' => array('class' => 'StaticPage''parameters' => 'html/feedback.html')
    );

    $factory =& new EventFactory();
    $event   =& $factory->createEvent($events[$_GET['page']]);
    $event->execute(); 
    The factory is just another indirection, but it's a useful one, because it eliminates the overhead incurred earlier. Now, only a single object is actually created, namely the one that represents the event that will be executed.

    There are still various problems with this simple solution. For example, an event class can only accept a single argument in its constructor. Also, errors aren't handled properly. Personally, I don't like the idea of specifying the event table in code. Why not write one in a separate file, and let the rest of the code use it automatically? For example:

    PHP Code:
    key      event      parameters
    home     
    StaticPage page     'html/home.html'
    news     NewsPage   filemask 'news/*.html'
    feedback StaticPage page     'html/feedback.html' 
    Registering an event is now a simple matter of adding a line to the event table. There's need to edit any code at all.

    Of course, the code I presented here is in no way as powerful as the combined code posted by everybody else in this thread. Although the missing functionality can be added pretty easily without adding too many lines of code, that's not the point of this post. My point is that I think we should take care not to 'overdesign' our solutions. Every problem should be solved in a simply a manner as possible. Adding indirection after indirection may result in a design that looks good on paper, but does it actually work better? I don't think so. Simple is best, is my opinion...

    Vincent

  9. #34
    SitePoint Zealot
    Join Date
    Dec 2001
    Location
    Ontario, Canada
    Posts
    141
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I've been abit busy, as I'm sure we all have.
    Here is a simple event 'table' or 'registry':
    PHP Code:
    <?
        
    if( !defined'ERR_LVL' ) ) {
            
    define'ERR_LVL'E_USER_WARNING );
        }
        
        class 
    Event 
            function 
    raise$params ) { 
                return( 
    '\n<b>Unhandled Event</b><br />\n' ); 
            } 
        }
        
        class 
    EventHandler {
            var 
    $events = array();
            
            function 
    geteventnames() {
                return( 
    array_keys$this->events ) );
            }
            
            function 
    addevent$name, &$object ) {
                if( !
    is_object$object ) ) {
                    
    trigger_error'<b>EventHandler Error:</b> Method <i>addevent()</i>, second parameter is not an object'ERR_LVL );
                    return( 
    false );
                }
                if( !
    is_subclass_of$object'Event' ) ) {
                    
    trigger_error'<b>EventHandler Error:</b> <i>' get_class$object ) . '</i> is not derived from <i>Event</i>'ERR_LVL );
                    return( 
    false );
                }
                
                
    $this->events[$name][] = &$object;
                return( 
    true );
            }
            
            function 
    callevents$name$params null ) {
                if( 
    is_array$this->events[$name] ) ){
                    
    $num count$this->events[$name] );
                    for( 
    $idx 0$idx $num$idx++ ) {
                        
    $value .= $this->events[$name][$idx]->raise$params );
                    }
                } else {
                    
    $value Event::raisenull );
                }
                return( 
    $value );
            }
        }
    ?>
    It's very simple, and straight forward..
    this is also setup to handle more then one type of event, and more then one event per type.

    It can also be used as a standalone class, or part of a composition.

    I'm in the middle of something at the moment, I'll give an example of how you can use it later, if one is needed.
    Last edited by AcidReign; Oct 31, 2002 at 05:52.
    Web Hound
    $x='010000010110001101101001011001000101001001100101011010010110011101101110';
    for($i=0;$i<strlen($x);$i+=8)print(chr(bindec(substr($x,$i,8))));

  10. #35
    SitePoint Wizard gold trophysilver trophy
    Join Date
    Nov 2000
    Location
    Switzerland
    Posts
    2,479
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Think you're completely right Vincent. And looking at your design, reckon it could scale nicely from a simple, but limited solution to a more complicated but flexible solution, as required.

    One further problem I see if Vincents example is you're tied to the $_GET variable $page.

    Been thinking about the problem of how deal with multiple events. My opinion is the best way is to handle them in the ordered they are gathered from various sources (my first attempt dealt with them in the order they were registered - in other words how they appeared in Vincents $events array above). So if we use something like phils classes up there, perhaps in a single class called EventReceiver, extending Vincents example it might be;

    PHP Code:
    <?php
    // This could be in a file - XML even
    $eventRegister = array(
        
    'email'    => array('handler' => 'EmailHandler',
                            
    'widgets' => array (
                                                
    'FormControl',
                                                
    'FormResponse',
                                                )),
        
    'login'    => array('handler' => 'LoginHandler',
                            
    'widgets' => array (
                                                
    'FormControl',
                                                
    'FormResponse',
                                                )),
        
    'news'     => array('handler' => 'NewsHandler'  ,
                            
    'widjets' => array (
                                                
    'TableControl'
                                                
    )),
        
    'home'     => array('handler' => 'DefaultHandler',
                            
    'widgets' => array (
                                                
    'StaticControl'
                                                
    )),
        
    'feedback' => array('handler' => 'FeedbackHandler',
                            
    'widgets' => array (
                                                
    'StaticControl'
                                                
    ))
    );

    // Get all the incoming events
    $receiver=& new EventReceiver();
    $receivedEvents=$receiver->listEvents();

    $factory =& new EventFactory();
    foreach (
    $receivedEvents as $name => $values) {
        
    $event=& $factory->createEvent($events[$name],$values);
        
    $event->execute();
    }

    ?>
    Or something like that. Again I'm think not perfect - getting too complex...

    If I read Martin Fowler right, he's saying you have two choices - one is to use hardcoded conditional statements but keep the incoming data flexible (when you need a new $_GET variable, for example, you "just" code the procedural logic to deal with it) or, to use classes to deal with handling, you have to define a fixed "namespace" which incoming variables have to be received on, e.g. something like;

    http://www.domain.com/{packagename}/{classname}/{methodname}/{parameter_1}/.../{parameter_n}

    Anyway - still thinking.

    Looking at you code Vincent - great way to do things - think I can see where you're going with that.

  11. #36
    SitePoint Wizard gold trophysilver trophy
    Join Date
    Nov 2000
    Location
    Switzerland
    Posts
    2,479
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    One other idea - what about using custom error handlers and trigger_error to "invoke" events? Just a thought (looking at AcidReigns code)

  12. #37
    SitePoint Zealot
    Join Date
    Dec 2001
    Location
    Ontario, Canada
    Posts
    141
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Harry: can you elaborate on that?
    Web Hound
    $x='010000010110001101101001011001000101001001100101011010010110011101101110';
    for($i=0;$i<strlen($x);$i+=8)print(chr(bindec(substr($x,$i,8))));

  13. #38
    killall -9 lusers
    Join Date
    Oct 2002
    Location
    Cincinnati, Ohio, USA
    Posts
    390
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally posted by HarryF
    One other idea - what about using custom error handlers and trigger_error to "invoke" events? Just a thought (looking at AcidReigns code)
    I think that would be pretty sloppy unless the event was actually a response to an error.

  14. #39
    SitePoint Evangelist
    Join Date
    Oct 2001
    Posts
    592
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    One further problem I see if Vincents example is you're tied to the $_GET variable $page.
    Yes, but that's because my example code was bare code. If I put it in a class, I would tie it to a variable passed to an object on construction. Imagine a class EventTable that works like this:

    PHP Code:
    $handler =& new EventTable('pages.dat');
    $event   =& $handler->getEvent($_GET['page']);
    $event->execute(); 
    This EventTable stores a single event table. In this particular case I load the table from a file and then request the correct event by passing $_GET['page']. I could also implement the EventTable so that it loads tables from a database, or allows them to be created dynamically. The call to getEvent in this case receives the value of $_GET['page'], but it could of course come from anywhere.

    Been thinking about the problem of how deal with multiple events
    I've been thinking about them too. Generally, I think there are two different cases:
    1. Events having equal priority. These are on the same level.
    2. Events dependent on other events. These are in multiple levels.

    In the first case, I would create multiple events, one for each event table. These can then be processed in some order. For example:

    PHP Code:
    $pageTable =& new EventTable('pages.dat')
    $userTable =& new EventTable('user.dat')
    // ...
    $pageEvent =& $pageTable->getEvent($_GET['page']);
    $userEvent =& $userTable->getEvent($_GET['user']);
    // ...
    $userEvent->execute();
    $pageEvent->execute(); 
    I think using multiple tables makes sense, because the events are disjunct; they are based on different, non-linked variables ('page' and 'user' in this case).

    Of course, you can write some code on top of the EventTables class that handles this case (builds an array of event tables and then processes them in some order), but I think this case almost never occurs...

    The second case is, I think, much more common: an event is triggered, which in turn triggers another event. A user selects the page 'documentation', and on that page he selects the 'introduction' section. The 'section' event table makes no sense for any other page than the one with the documentation. This case can easily be solved by using an EventTable inside a triggered event. Events can be nested infinitely, as long as they aren't based on the same name.

    I think that in web applications few events actually co-exist with one another on the same lever (the first case). You might have an event table for the page and the user, but if the user triggers a 'logout' event, this could easily result in a redirect to another page, as he could otherwise see a page only available to users that are logged in. So in that case the page-event handler must be disabled. By nesting the page-handler inside the user-handler, this is easily solved.

    Anyway, just because I can't think of a good example of a web-application using multiple events at the same level, that doesn't mean they don't exist...

    One other idea - what about using custom error handlers and trigger_error to "invoke" events? Just a thought (looking at AcidReigns code)
    When you're using some kind of event handling system, two different things can go wrong:
    1. User errors: events are left unspecified, or have the wrong value (someone specifies a page not in the event table, for example). These should be handled gracefully, and not trigger real PHP errors. Use default values for missing ones, for example.
    2. Programmer errors: tables are defined incorrectly, or events are passed illegal (static) arguments. In large systems it can be a good idea to detect and report these errors to the programmer. On the other hand, these checks should not impose overhead on the application itself, as a correct application has correct event tables, and thus no such errors.

    Vincent

  15. #40
    SitePoint Wizard gold trophysilver trophy
    Join Date
    Nov 2000
    Location
    Switzerland
    Posts
    2,479
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Flying in the face of reason for a moment, here's the scam with PHP's error handling;

    PHP Code:
    <?php
    // Some demo class
    class MyEvent {
        function 
    MyEvent () {
            echo (
    'Hello World!');
        }
    }

    // Override the E_USER_NOTICE constant with our own name
    define ("EVENT",E_USER_NOTICE);

    // Set what errors we will respond to, including EVENT
    // Note that this overrides PHP ini
    error_reporting  (E_ERROR E_WARNING E_PARSE EVENT);

    // Define the error handling function
    function myErrorHandler ($errno$errstr$errfile$errline) {
        switch (
    $errno) {
            case 
    EVENT:
                
    $event=& new $errstr;
                break;
            default:
                die (
    "Error in $errfile on $errline:[$errno$errstr<br />\n");
                break;
        }
    }

    // Tell PHP to use the error handler, overriding the in
    // built handler - all errors go by our function
    $eHandler=set_error_handler('myErrorHandler');

    // Trigger an event
    trigger_error ('MyEvent'EVENT);
    ?>
    It may be possible to define a class instead of a function as the error handler - yet to experiment with that.

    What this does mean is it becomes very easy to trigger an event from anywhere.

  16. #41
    SitePoint Wizard gold trophysilver trophy
    Join Date
    Nov 2000
    Location
    Switzerland
    Posts
    2,479
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Wait a second - now we get into some serious hacking

    The message you send with trigger_error() must be a string. But if you wanted to send an array (or even an object) you can use serialize()

    From the manual;

    To make the serialized string into a PHP value again, use unserialize(). serialize() handles all types, except the resource-type. You can even serialize() arrays that contain references to itself. References inside the array/object you are serialize()ing will also be stored.

    Note: In PHP 3, object properties will be serialized, but methods are lost. PHP 4 removes that limitation and restores both properties and methods. Please see the Serializing Objects section of Classes and Objects for more information.
    So for a simple example using an array;

    PHP Code:
    <?php
    // Some demo class
    class MyEvent {
        function 
    MyEvent () {
            echo (
    'Hello World!');
        }
    }

    // Override the E_USER_NOTICE constant with our own name
    define ("EVENT",E_USER_NOTICE);

    // Set what errors we will respond to, including EVENT
    // Note that this overrides PHP ini
    error_reporting  (E_ERROR E_WARNING E_PARSE EVENT);

    // Define the error handling function
    function myErrorHandler ($errno$errstr$errfile$errline) {
        switch (
    $errno) {
            case 
    EVENT:
    //            $event=& new $errstr;

                // Convert the string back to it's original form
                
    $errstr=unserialize($errstr);
                echo ( 
    "<pre>" );
                
    print_r ($errstr);
                echo ( 
    "</pre>" );
                break;
            default:
                die (
    "Application Error:[$errno$errstr<br />\n");
                break;
        }
    }

    // Tell PHP to use the error handler, overriding the in
    // built handler - all errors go by our function
    $eHandler=set_error_handler('myErrorHandler');

    $array=array("one","two");
    // turn the array into a serialized string
    $array=serialize ($array);

    // Trigger an event
    trigger_error ($arrayEVENT);
    ?>
    It get's interesting...

    Looks like the error handler itself must be a function - had a quick go at defining a class, even using 'myErrorHandler::myErrorHandler' without success.
    Last edited by HarryF; Oct 31, 2002 at 08:51.

  17. #42
    SitePoint Wizard gold trophysilver trophy
    Join Date
    Nov 2000
    Location
    Switzerland
    Posts
    2,479
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    OK - going for the triple post, here's one way this could be used;

    PHP Code:
    <?php
    /* Event Trigger Script
     * Usage:
     * Include this file in all your scripts
     * You can then fire off an event from anywhere using
     * 
     * triggerEvent ($Object,$nameOfObjectMethodtoExecute,$params);
     * 
     */

    /* Override the E_USER_NOTICE with EVENT */
    define ('EVENT',E_USER_NOTICE);

    /* Set PHP's error reporting level */
    error_reporting  (E_ERROR E_WARNING E_PARSE EVENT);

    /* Define the event trigger "error" handling function */
    function eventTrigger ($eventType,& $event$errfile$errline) {
        switch (
    $eventType) {
            case 
    EVENT:
                
    $event=unserialize($event);
                
    $event->object->{$event->execute}($event->params);
                break;
            default:
                die (
    "[$eventType] Error in $errfile on $errline$event<br />\n");
                break;
        }
    }

    /* Tell PHP to use the eventTrigger handler
     * This overrides PHP's normal error handling
     */
    $eventTrigger=set_error_handler('eventTrigger');

    /* Use this function to fire off events */
    function triggerEvent (& $object,$execute,$params=null) {
        
    $event=new stdClass;
        
    $event->object=$object;
        
    $event->execute=$execute;
        
    $event->params=$params;
        
    $event=serialize($event);
        
    trigger_error ($eventEVENT);
    }
    ?>
    PHP Code:
    <?
    // Include the above script
    require_once('eventTrigger.php');

    class 
    MyEvent {
        var 
    $msg;
        function 
    MyEvent () {
            
    $this->msg='Hello ';
        }
        function 
    display ($name) {
            echo (
    $this->msg.$name);
        }
    }

    $myEvent=& new MyEvent();

    triggerEvent($myEvent,'display','Harry');
    ?>
    Thinking hard about this, I'm not sure if we've actually gained anything here - every time I think too hard about this stuff, brain melts down.

    May be someone else can work out if this is useful.

  18. #43
    SitePoint Wizard gold trophysilver trophy
    Join Date
    Nov 2000
    Location
    Switzerland
    Posts
    2,479
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Wait a second - think we're getting there (sorry - fourth in a row but can't help myself);

    Using the eventTrigger script;

    PHP Code:
    require_once('eventTrigger.php');

    class 
    MessageOne {
        var 
    $msg;
        function 
    MessageOne () {
            
    $this->msg='Hello ';
        }
        function 
    display ($name) {
            echo (
    $this->msg.$name."<br />");
        }
    }

    class 
    MessageTwo {
        var 
    $msg;
        function 
    MessageTwo () {
            
    $this->msg="See you on ";
        }

        function 
    output ($day) {
            echo ( 
    $this->msg.$day."<br />");
        }
    }

    // Here's a list of events like Vincents up there

    $events=array (
        
    'name'=>array ('class'=>'MessageOne','accessor'=>'display'),
        
    'appointment'=>array ('class'=>'MessageTwo','accessor'=>'output')
        );

    // I use $_GET here for simplicity - this could
    // be Phils classes for an alternative example

    foreach ($_GET as $event => $param) {
        if (
    array_key_exists($event,$events)) {
            
    $thisEvent=& new $events[$event]['class'];
            
    $thisExecute=$events[$event]['accessor'];
            
    triggerEvent($thisEvent,$thisExecute,$param);
        }
    }
    ?> 
    Here, the events will happen in the order they're given to the server, e.g.

    1. http://localhost/event.php

    .. Displays nothing

    2. http://localhost/event.php?name=Harry

    Displays:
    Code:
    Hello Harry
    3. http://localhost/event.php?name=Harry&appointment=Tuesday

    Code:
    Hello Harry
    See you on Tuesday

    4. http://localhost/event.php?appointment=Tuesday&name=Harry

    Code:
    See you on Tuesday
    Hello Harry
    Now this doesn't incorporate Vincents last suggests right now, but I think some tuning of the event "tables" (the above $events variable) could get that right.

    The only further thing that might be worth modifying is being able to pass multiple method names to execute, in an array for example, to the error Handling function.

    I like this because the code is minimal, fairly generic and simple to use.
    Last edited by HarryF; Oct 31, 2002 at 10:39.

  19. #44
    As the name suggests... trickie's Avatar
    Join Date
    Jul 2002
    Location
    Melbourne, Australia
    Posts
    678
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Go hard or go home

  20. #45
    killall -9 lusers
    Join Date
    Oct 2002
    Location
    Cincinnati, Ohio, USA
    Posts
    390
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    What happens when your script actually throws an E_USER_NOTICE?

    I still don't like the idea of b a s t a r dizing the trigger_error() function that way.

    Couldn't you just write a function that behaved like trigger_error() but didn't actually handle errors?

  21. #46
    SitePoint Wizard gold trophysilver trophy
    Join Date
    Nov 2000
    Location
    Switzerland
    Posts
    2,479
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    E_USER_NOTICE is only generated by trigger_error() - i.e. only the code we write generates this. The same goes for E_USER_WARNING and E_USER_ERROR.

    So there's a trade off in that we lose that error level to use in conjunction with trigger_error(). But in a way, this is the purpose of these three error levels.

    Say, for instance, you ran a giant forum and wanted to warn your users to log off, because you're about to do maintenance - perhaps you'd use trigger_error() with E_USER_NOTICE to make everyone see a message "Site will be down in 15 minutes". Course there's other ways to achieve the same but that could work out quite elegant.

    In this case, we're turning the purpose upside down - rather that using the error level to notify the user, we're using it so the user can tell the application what to do.

    And if we really want to have loads of custom error messages, we could simply use E_USER_WARNING like,

    PHP Code:
    trigger_error("Code 54362: That number is too big"E_USER_WARNING); 
    What's good about trigger_error, is it already has an API, it's fast (compared to some classes we write) and is guaranteed to work from anywhere.

    Some other interesting things been coming across. Seems there is a way to specify a class method, using a workaround, as the default error handler.

    Also, on a related subject, using output buffering, it's possible to buffer output in stages, either be "nesting" buffers within each other, or repeatedly writing to, caching then flushing the buffer.

    This could be used to assign the output of a class to the buffer then store it in a file with an expiry date. Next time that class is going to be used, you check to see if there's a cached version which hasn't expired first and if so, use that instead of the class. That means for a database query where the results only change once a week say, you could have it an expiry of that long.

    Anyway - all interesting stuff.

  22. #47
    SitePoint Wizard gold trophysilver trophy
    Join Date
    Nov 2000
    Location
    Switzerland
    Posts
    2,479
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    OK - about to go on holiday so not much time. Attached is a ZIP with some classes and a demo that shows event handling using PHP's errors. It need more work of course - the real error handling doesn't work correctly yet. Also want to make use of output buffering to allow for dynamic caching of output. Finally I'm only working with $_GET right now.

    But it shows the events concept.

    To configure it, everything is done in config.php. "Handlers" go in the handlers directory.

    The overall idea of this code is you place all your own code inside the "SiteContainer". You use handlers to fire off your own stuff (be they objects, procedural scripts or whatever).

    There are two types of event I've defined;

    Static Events - these should always be run no matter what incoming requests there are from a user. Things like the PageHeader, sessions, security etc. Also see the Form handlers.

    Dynamic Events - these are only run when a user does "something", such as entering their name.

    The way events are processed is kind of 3D;

    In config.php you'll see;

    $staticHandlers[0]
    $staticHandlers[1]
    $dynamicHandlers[0]

    First to be processed is anything in $staticHandlers[0]

    Then $dynamicHandlers[0] is examined and events registered there are processed in the order which the events were sent.

    Then $staticHandlers[1] is processed (and after that $dynamicHandlers[1] if it existed).

    Anyway - makes an interesting toy.
    Attached Files Attached Files

  23. #48
    SitePoint Guru
    Join Date
    Oct 2001
    Posts
    656
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Over the past few weeks I've been thinking a lot about how to make a generic event handling mechanism. I've also re-read this thread and I'd like to make a few comments on some of the things discussed.

    Originally posted by HarryF
    Been thinking about the problem of how deal with multiple events. My opinion is the best way is to handle them in the ordered they are gathered from various sources (my first attempt dealt with them in the order they were registered - in other words how they appeared in Vincents $events array above). So if we use something like phils classes up there, perhaps in a single class called EventReceiver, extending Vincents example it might be
    I think you are mixing things up a bit. An application can only respond to a single event at a time, you can not send more than one event to the application simultaneously.

    If I understand you correctly, you are probably thinking about a situation like this. The user requests a page for adding a news item. The user must be logged in to access this page. So the script would have to execute an event/command for the login cookie *and* one for the add news page.

    When in fact there is only one 'event' that is executed here: the add news page. How this event is executed depends on whether there is a valid login cookie present. If that cookie is not present, the event should fire up a login page, otherwise it should just present the news page to the user.

    Originally posted by voostind
    The second case is, I think, much more common: an event is triggered, which in turn triggers another event. A user selects the page 'documentation', and on that page he selects the 'introduction' section. The 'section' event table makes no sense for any other page than the one with the documentation. This case can easily be solved by using an EventTable inside a triggered event. Events can be nested infinitely, as long as they aren't based on the same name.
    Same here. Since the web is - by nature - stateless, any event or request is standalone. Of course we use things like sessions to maintain state, but in essence it is still stateless.

    So, continuing voostind's example: a user selects the documentation page and the introduction page. Because of this stateless nature of the web, these requests can be made in any order. A user could for example first access the introduction page from a bookmark and then click on a link to the documentation page. Maybe I'm completely missing the point, but I think that supporting 'multiple events' in a web application is a bit pointless, because they are in fact only single events.

  24. #49
    killall -9 lusers
    Join Date
    Oct 2002
    Location
    Cincinnati, Ohio, USA
    Posts
    390
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I'd like to second that, unless someone can convince me otherwise.

  25. #50
    SitePoint Zealot
    Join Date
    Dec 2001
    Location
    Ontario, Canada
    Posts
    141
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Attached is the current version of my Event Handling class, with an ( extreamly basic ) example.
    Attached Files Attached Files
    Web Hound
    $x='010000010110001101101001011001000101001001100101011010010110011101101110';
    for($i=0;$i<strlen($x);$i+=8)print(chr(bindec(substr($x,$i,8))));


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
  •