Queue

Small, short code snippets that other people may find useful. Do you have a good regex that you would like to share? Share it! Even better, the code can be commented on, and improved.

Moderator: General Moderators

Post Reply
McGruff
DevNet Master
Posts: 2893
Joined: Thu Jan 30, 2003 8:26 pm
Location: Glasgow, Scotland

Queue

Post by McGruff »

Code: Select all

<?php

class Queue
{

    var $objects_list;


    function Queue($objects_list)
    {
        $this->objects_list =& $objects_list;
    }

    function loadObjects()
    {        
        while(!is_null($object = array_shift($this->objects_list)))
        {
            include($object['script']);
            ${$object['class_name']} =& new $object['class_name']($this);
        }
    }

}

?>
array_shift allows each of the objects to write back to the $objects_list property while it is being iterated over. Hence the script can be dynamically reprogrammed depending on the results of each object's execution. Objects can add or delete items from the list - or even load themselves again for another go.

This was one of those 2:00am eureka moments which seemed to hold lots of promise but for which I confess I've never found any real use (well, serving up web pages never gets that complicated I guess). I thought I'd post it here in case it might give anyone else some ideas - let me know if so.
Last edited by McGruff on Wed Aug 10, 2005 12:40 am, edited 5 times in total.
User avatar
lazy_yogi
Forum Contributor
Posts: 243
Joined: Fri Jan 24, 2003 3:27 am

Post by lazy_yogi »

Eclipse has the iterator pattern down pat
http://www.students.cs.uu.nl/people/voostind/eclipse/

You need the following methods defined for an iterator

next()
previous() // optional
getCurrent()

so you can do

$iterator = new SomeIterator($someObjectToIterateOver);
while ($iterator->next())
{
$currentItem = $iterator->getCurrent();
// do somethien with item
}
McGruff
DevNet Master
Posts: 2893
Joined: Thu Jan 30, 2003 8:26 pm
Location: Glasgow, Scotland

Post by McGruff »

Rgr but what I'm getting at here is a mechanism to reset the array while it is being iterated over - hence allowing each object that gets loaded to reprogram the script.

Suppose you were making a cake. "Add ingredient" objects might add ingredients to a mixing bowl. A "mix" object might run then check to see how well mixed the dough is. Too dry? Load up the "add milk" object again, and then the "mix" object to mix it in. A "bake" object might need to reload itself if the cake isn't quite done, and so on.

A script that can re-write itself as it executes seems like a powerful tool but I'm not sure if it's much use for simple programming tasks like serving up web pages. Really I was thinking about artificial intelligence: a decision such as what jacket to buy can depend on straightforward, logical factors such as what season it is, is it waterproof etc as well as subtle emotional factors such as do I like the colour, what is everybody else wearing this winter and does my bum look big in this?

A "dynamically reprogrammable object iterator" (for want of a better term) might be one way to allow a whole series of factors to interact en route to the final decision / output process. The exact path taken can be intelligently altered by each object loaded by the iterator.
User avatar
lazy_yogi
Forum Contributor
Posts: 243
Joined: Fri Jan 24, 2003 3:27 am

Post by lazy_yogi »

ahh ok .. I re-read it.

Interesting .. but an example application (or part of an application) would make it clearer and show where it might be used

Eli
Straterra
Forum Regular
Posts: 527
Joined: Mon Nov 24, 2003 8:46 am
Location: Indianapolis, Indiana
Contact:

Post by Straterra »

Um..Call me an idiot, but what is a iterator?
McGruff
DevNet Master
Posts: 2893
Joined: Thu Jan 30, 2003 8:26 pm
Location: Glasgow, Scotland

Post by McGruff »

Straterra wrote:Um..Call me an idiot, but what is a iterator?
Something which repeats an operation.

An array iterator, for example, might have a next() method to get the next element in the array and would return false when the end of the array is reached (no more elements to return).

Yogi: although I do use this it's not in anything which needs to reset the array while it's being processed. It's an abstract "feedback" mechanism - a pattern maybe - rather than a piece of code which does something in itself. I thought it might be interesting.
User avatar
lazy_yogi
Forum Contributor
Posts: 243
Joined: Fri Jan 24, 2003 3:27 am

Post by lazy_yogi »

Straterra wrote:Um..Call me an idiot, but what is a iterator?
Iterator - A data type used to mark a position in a collection of data (e.g. a linked list) and to move from item to item within the collection.

For example you could have an object which keeps the position in an array. You might have these methods in the class :
next() which moves up one position
preious() which moves back one position
getCurrent() which gets the element that at that position
begin() which resets the position to the beginning
end() which resets the position to the last element.

so you could use it

Code: Select all

$iter = new Iterator($object_maybe_array)
while ($iter->next()) 
&#123;
    print $iter->getCurrent(); // or you could do more with this item.
&#125;
but an iterator can be applied to other objects, not just arrays.
User avatar
BDKR
DevNet Resident
Posts: 1207
Joined: Sat Jun 08, 2002 1:24 pm
Location: Florida
Contact:

Re: Queue

Post by BDKR »

McGruff wrote:

Code: Select all

<?php

class Queue
{

    var $objects_list;


    function Queue($objects_list)
    {
        $this->objects_list =& $objects_list;
    }

    function loadObjects()
    {        
        while(!is_null($object = array_shift($this->objects_list)))
        {
            include($object['script']);
            ${$object['class_name']} =& new $object['class_name']($this);
        }
    }

}

?>
array_shift allows each of the objects to write back to the $objects_list property while it is being iterated over. Hence the script can be dynamically reprogrammed depending on the results of each object's execution. Objects can add or delete items from the list - or even load themselves again for another go.

This was one of those 2:00am eureka moments which seemed to hold lots of promise but for which I confess I've never found any real use (well, serving up web pages never gets that complicated I guess). I thought I'd post it here in case it might give anyone else some ideas - let me know if so.
This is a cool hunk of code (!), but in the strictest sense, this isn't a queue. A queue is a lot like a stack save for one important difference. A queue is FIFO (First In First Out) as opposed to a stack being FILO (First In Last Out). If I'm not mistaken, the ADT extension is supposed to bring this stuff to PHP in version 5 as an extension. I wrote a class and some procedures to mimmic this.

http://mgaps.highsidecafe.com/tools/queues.txt

Not to take away from what you did. I just thought I'd mention it. :)

Cheers,
BDKR
McGruff
DevNet Master
Posts: 2893
Joined: Thu Jan 30, 2003 8:26 pm
Location: Glasgow, Scotland

Post by McGruff »

Thanks for the link.

I'm self-taught so I don't always pick the correct terms :) A "pipe" possibly?

The class has now evolved quite a bit. I added an observer pattern so that objects in the pipe (or whatever) are both observable to and observers of each other. It's aimed at assisting a "manager" type class load a bunch of objects, so the manager also listens to the pipe objects.

So far I've been using it in a (yet another) framework to run pre and post client output tasks, as well as in a ClientPage printer.

Pipe objects can be "navigators" (decide what to do) or "agents" (do it). So, a form processing navigator could examine a submission and, if it checks out, load a processing agent etc.

ClientPage is a print manager tasked with loading a model, a view & printing the page (possibly not MVC but then I don't agree with the way MVC is applied to web apps). Since pages are normally composed of several sub-models (header, footer, etc), the pipe can load all the objects and ClientPage can listen for the page vars output, thus building a complete page model. A HeadHtml pipe object/sub-model (<head> tag stuff) can listen to other sub-models to gather a title & keywords.

Sometime soon I'll need to post it all to get some feedback.
User avatar
BDKR
DevNet Resident
Posts: 1207
Joined: Sat Jun 08, 2002 1:24 pm
Location: Florida
Contact:

Post by BDKR »

McGruff wrote: Thanks for the link.

I'm self-taught so I don't always pick the correct terms :) A "pipe" possibly?
Me too. I just happened to get this huge menacing looking book called "Fundamental Algorthms" by Donald Knuth. And besides, isn't this board for trading info with freinds?

I can see why one would call it a queue for the most part. And come to think of it, perhaps I'm being to strict. Let me ask this: Are objects regularly pushed out of the pipe (:wink:) and new ones added? It doesn't appear as so, but if that's the case, then it certainly is behaving like a queue.

I'm inclined to go with the term 'pool' as this implies a 'pool' of things (in this case objects) that aren't regularly being pushed, popped, or shfited off the array.
McGruff wrote: Sometime soon I'll need to post it all to get some feedback.


Please do! It's allways cool when clever people show off those clever things they do.

Cheers,
BDKR
McGruff
DevNet Master
Posts: 2893
Joined: Thu Jan 30, 2003 8:26 pm
Location: Glasgow, Scotland

Post by McGruff »

Yes, objects can be added/deleted etc so perhaps it is a queue after all. Just to confuse matters further, I've taken to calling it "DynamicEngine".

Here's the latest version & some notes. In a few weeks or so I'll maybe stick up a few pages somewhere showing how it can be used as the core of a php framework.

CLASS: DynamicEngine

A variation on the factory theme. DE is intended to assist some kind of manager-type class: loads a bunch of objects in a processing pipe or queue.

(1) loaded objects can reprogram the objects list
(2) objects in the pipe are both observers of and observable to each other
(3) the $manager object is also an observer of pipe objects

DE loads classes defined in an $objects_list array. The array contains names of classes to load and their script paths eg:

Code: Select all

$objects_list[0]['class']  = 'Foo';
            $objects_list[0]['script'] = 'path/to/file1.php';
            $objects_list[1]['class']  = 'Bar';
            $objects_list[1]['script'] = 'path/to/file2.php';
It's occasionally useful to pass args to individual objects via the meta data array- just add another key (see loadObjects).

The reprogrammable behaviour is obtained by allowing objects in the list to edit the array while it is being looped over. They may add other objects, load themselves again for another go, reset the entire list, etc. Obviously, a feedback mechanism creates a risk of infinite loops - DE won't stop you doing that should you try.

Chained messages (ie a message triggered in repsonse to receipt of another message) carry the same risk.

An array of args can be passed from $manager for use by pipe objects (see getArgs). At present, that - and $manager observation of pipe objects - is as far as any interaction between the two goes. A minor re-write could pass the $manager itself to pipe objects, should they require access to $manager properties or methods.

The reprogrammable mechanism & message system could possibly be used to create quite complex behaviours. Haven't really explored that as yet. The whole thing originated from amateur musings on AI (which went nowhere). I'm hoping it will be a flexible, powerful tool but time will tell just how easy it is to get along with.

Code: Select all

class DynamicEngine
{        
    // public
    var $args;

    /*
        param (object) $manager - the object assisted by DE        
    */
    function DynamicEngine(&$manager) 
    {
        $this->manager  =& $manager;
        $this->args         =& $manager->getArgs();
    }

    /*
        (1) instantiates classes listed in the $objects_list array,
        (2) attach observables
        (3) tells each object to "start" (docs: PipeObjects interface)

        NB: do not broadcast chained messages from pipe object constructors (object isn't registered as observer at this stage, hence chained messages cannot work).
    */
    function loadObjects()
    {        
        while(!is_null($object_meta = array_shift($this->objects_list)))
        {
            include_once($object_meta['script']);
            $class  = $object_meta['class']; 
            $ob     =& new $class($this, $object_meta);

            $this->pipe_objects[$class] =& $ob; // attach observable
            
            $ob->start();    
        }
    }

    /*
        OBJECTS LIST
        
        Methods to set $objects_list meta data or edit array elements.
        
        Pipe objects are free to use these methods to delete
        objects from the list, add new objects, or even load 
        themselves again for another go. 
        
        If you use that feature, watch out for infinite loops... 

        param (array) $objects_list meta data eg:
    */

    // destructive set / reset
    function setObjectsList($objects_list)
    {
        $this->objects_list = $objects_list;
    }

    // add to start of list (non-destructive)
    function prependObjects($objects_list)
    {
        foreach($objects_list as $value)
        {
            array_unshift($this->objects_list, $value);
        }
    }

    // add to end of list (non-destructive)
    function appendObjects($objects_list)  
    {
        foreach($objects_list as $value)
        {
            array_push($this->objects_list, $value);
        }
    }

    /*
        ARGS

        Pass $args obtained from $manager through to pipe objects. 
        return (array) $args
    */
    function &getArgs()
    {
        return $this->args;
    }
    
    /*
        NOTIFY OBSERVERS
    */
    
    /*
        A "broadcast" message on pipe objects channel. 
        Received by all instantiated (!) pipe objects.
        param (string) $type
        param (mixed) $payload
    */
    function notifyPipeObjects($type, &$payload)
    {
        foreach(array_keys($this->pipe_objects) as $class)
        {
            $this->pipe_objects[$class]->listen($type, $payload);
        }
    }

    /*
        "Narrow-cast" messages on $manager channel
        param (string) $type
        param (mixed) $payload
    */
    function notifyManager($type, &$payload)
    {
        $this->manager->listen($type, $payload);
    }


}
PS: messages contain a $type and $payload.

$type is used to dynamically call a method in the observer; $payload is the, er, message payload - string, array, object - whatever.
Post Reply