SitePoint Sponsor

User Tag List

Results 1 to 11 of 11
  1. #1
    ********* wombat firepages's Avatar
    Join Date
    Jul 2000
    Location
    Perth Australia
    Posts
    1,717
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    keeping it in the family ... more than once ?

    Hi , I think I want what seems to me to be multiple inheritance which , aside from the fact that PHP does not provide such , I also hear is an OOP no-no as well ?

    Anyway I am mapping xml (more often xhtml) to a php-gtk interface , after the xml parsing and validation is done I am first creating the basic containers before moving onto signals and such.

    now ideally I would create my custom widgets by extending the php-gtk built in widgets , e.g. what will essentially become a frame (think fieldset in html) could be ..

    PHP Code:
    <?
    class gfi_fieldset extends GtkFrame{
    var 
    $label ;/*{obj} gtklabel*/
         
    function gfi_fieldset$label ){
            
    $this->GtkFrame$label ) ;
         }
    }
    ?>
    this gives me instant access to all the built in methods of GtkFrame like set_label() etc .
    it also gives me access to a lot of GtkFrames inherited methods such as set_usize() blah , so its really nice.

    however also ideally I would like to extend my own gfi() base class which will give me easy access to all of my own custom methods that I may to to utilise with the form elements

    PHP Code:
    <?
    class gfi_container{
        function 
    set_bg_pixmap(){
              
    /* 
              setting a background image in php-gtk is quite a convoluted 
              process so this is one example , which would be useful for      
              container type objects
              */
        
    }
    }
     
    class 
    gfi_fieldset extends gfi_container{
    var 
    $label ;/*{obj} gtklabel*/
         
    function gfi_fieldset$label ){
             
    $this->gfi_container() ;
             
    /* now I have to do this */
             
    $this->fieldset = new GtkFrame() ;
          }
    }

    ?>
    I can still get at the GtkFrame methods but its messy eg ,

    $this->gfi_fieldset_obj->set_label( $label ) ;

    ...I could write wrappers for all native functionality but lifes too short ..
    any ideas or pointers ? , I have stuff that works but its ugly and full of workarounds.

  2. #2
    simple tester McGruff's Avatar
    Join Date
    Sep 2003
    Location
    Glasgow
    Posts
    1,690
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    An alternative to inheritance might be to make every object a property of every other class. That way they can all get at each others properties and methods much the same as with inheritance.

    Lose out on overiding but the big advantage is the classes don't get tied into an inheritance structure and can be called in other scripts in other combinations, if needed. And of course, no problems from multiple inheritance.

    If two objects are "linked" maybe instantiate one inside the other to reflect that link; if not don't. I wish I could explain what I meant by that.. It'll probably be kind of obvious if you try it the wrong way.
    Last edited by McGruff; Sep 15, 2003 at 08:14.

  3. #3
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I have stuff that works but its ugly and full of workarounds.


    I'm in the same boat as yourself here

    McGruff - Have you any examples to explain your solution ?

    Thanks

  4. #4
    simple tester McGruff's Avatar
    Join Date
    Sep 2003
    Location
    Glasgow
    Posts
    1,690
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Sorry I think posted that too quickly - I missed the bit of firepages code where $this->fieldset = new GtkFrame() ; adds a class as a property of another. That's all I meant to point out, and that you can do that either by instantiating classes within other objects or by passing them in as args to a method.

  5. #5
    ********* wombat firepages's Avatar
    Join Date
    Jul 2000
    Location
    Perth Australia
    Posts
    1,717
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi , cheers for the input , I (at the moment anyway ) am trying to go down that route but the other way around eg ...

    PHP Code:
    <?
    class gfi_frame extends GtkFrame
         
    gfi_frame$name ){
              
    $this->GtkFrame() ;
              
    $this->set_name$name ) ;
            
              
    $this->gfi = new gfi_tools$this ) ;
         }
    }
    ?>
    so all objects can access the utility functions in gfi_tools() , I still have to do this which I wanted to avoid ...

    $obj->gfi_tools->method( $args );

    but at least its a single access point for shared functionality , and saves a bit of typing , still hoping there is a cleaner way though.

    I was thinking of ...

    PHP Code:
    <?
    class gfi_frame extends GtkFrame
         
    gfi_frame$name ){
              
    $this->GtkFrame() ;
              
    $this->set_name$name ) ;
         }
     
         function 
    dodgy$method $args ){
             
    gfi_tools::$method$this $args );
         }
    }
    ?>

    but I guess thats bad juju ?

  6. #6
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Umm.... IMO The first example looks a lot cleaner ?

    [Off Topic]

    Not trying to hijack your thread Firepages, though since we both have a common problem maybe some one have provide a cleaner solution to the following classes ?

    PHP Code:
    class Widgets {
            
            function 
    Widgets() {
            }
            
            function 
    appendChild($dom$ele) {
                
    $node $dom -> append_child($ele);
                
                return 
    $node;
            }
            
            function 
    createElement($dom$ele) {
                
    $node $dom -> create_element($ele);
                
                return 
    $node;
            }
            
            function 
    createTextNode($dom$txt) {
                
    $text $dom -> create_text_node($txt);
                
                return 
    $text;
            }
            
            function 
    addAttribute($dom$attr$value) {
                
    $node $dom -> set_attribute($attr$value);
                
                return 
    $node;
            }
        }
        
        class 
    pageWidget extends Widgets {
            var 
    $dom;    
            var 
    $html;    
            var 
    $head;    
            var 
    $body;
            
            function 
    pageWidget(& $dom) {
                
    Widgets::Widgets(& $dom);
                
    //
                
    $this -> dom = & $dom;
            }
            
            function 
    create() {
                
    // begin
                
    $this -> html Widgets::createElement($this -> dom'html');
                
    $this -> head Widgets::createElement($this -> dom'head');
                
    $this -> body Widgets::createElement($this -> dom'body');
                
    // create actual page
                
    Widgets::appendChild($this -> dom$this -> html);
            } 
            
            function 
    addHead($ele) {
                
    Widgets::appendChild($this -> head$ele);
            }
            
            function 
    addBody($ele) {
                
    Widgets::appendChild($this -> body$ele);
            }
            
            function 
    finalise() {
                
    Widgets::appendChild($this -> dom$this -> head);
                
    Widgets::appendChild($this -> dom$this -> body);
            }
            
            function 
    show() {
                
    $this -> finalise();
                return 
    $this -> dom -> dump_mem(true);
            }
        }
        
        class 
    titleWidget extends Widgets {
            var 
    $dom;
            var 
    $node;
            
            function 
    titleWidget(& $dom) {
                
    $this -> dom = & $dom;
                
    //
                
    $this -> node Widgets::createElement($this -> dom'title');
            }
            
            function 
    create($msg) {
                
    $text Widgets::createTextNode($this -> dom$msg);
                
    Widgets::appendChild($this -> node$text);
            }
            
            function 
    fetch() {
                return 
    $this -> node;
            }
        }
        
        class 
    paraWidget extends Widgets {
            var 
    $dom;
            var 
    $node;
            
            function 
    paraWidget(& $dom) {
                
    $this -> dom = & $dom;
                
    //
                
    $this -> node Widgets::createElement($this -> dom'p');
            }
            
            function 
    create($msg) {
                
    $text Widgets::createTextNode($this -> dom$msg);
                
    Widgets::appendChild($this -> node$text);
            }
            
            function 
    addAttribute($attr$value) {
                
    Widgets::addAttribute($this -> node$attr$value);
            }
            
            function 
    fetch() {
                return 
    $this -> node;
            }
        }
        
        class 
    hrefWidget extends Widgets {
            var 
    $dom;
            var 
    $node;
            
            function 
    hrefWidget(& $dom) {
                
    $this -> dom = & $dom;
                
    //
                
    $this -> node Widgets::createElement($this -> dom'a');
            }
            
            function 
    create($msg) {
                
    $text Widgets::createTextNode($this -> dom$msg);
                
    Widgets::appendChild($this -> node$text);
            }
            
            function 
    addAttribute($attr$value) {
                
    Widgets::addAttribute($this -> node$attr$value);
            }
            
            function 
    fetch() {
                return 
    $this -> node;
            }
        }
        
        class 
    imgWidget extends Widgets {
            var 
    $dom;
            var 
    $node;
            
            function 
    imgWidget(& $dom) {
                
    $this -> dom = & $dom;
                
    //
                
    $this -> node Widgets::createElement($this -> dom'img');
            }
            
            function 
    create() {
            }
            
            function 
    addAttribute($attr$value) {
                
    Widgets::addAttribute($this -> node$attr$value);
            }
            
            function 
    fetch() {
                return 
    $this -> node;
            }
        }
        
        class 
    tableWidget extends Widgets {
            var 
    $dom;
            var 
    $node;
            
            function 
    tableWidget(& $dom) {
                
    $this -> dom = & $dom;
                
    //
                
    $this -> node Widgets::createElement($this -> dom'table');
            }
            
            function 
    create() {
            }
            
            function 
    addTable($node) {
                
    Widgets::appendChild($this -> node$node);
            }
            
            function 
    addAttribute($attr$value) {
                
    Widgets::addAttribute($this -> node$attr$value);
            }
            
            function 
    fetch() {
                return 
    $this -> node;
            }
        }
        
        class 
    trWidget extends Widgets {
            var 
    $dom;
            var 
    $node;
            
            function 
    trWidget(& $dom) {
                
    $this -> dom = & $dom;
                
    //
                
    $this -> node Widgets::createElement($this -> dom'tr');
            }
            
            function 
    create() {
            }
            
            function 
    addRow($node) {
                
    Widgets::appendChild($this -> node$node);
            }
            
            function 
    fetch() {
                return 
    $this -> node;
            }
        }
        
        class 
    tdWidget extends Widgets {
            var 
    $dom;
            var 
    $node;
            
            function 
    tdWidget(& $dom) {
                
    $this -> dom = & $dom;
                
    //
                
    $this -> node Widgets::createElement($this -> dom'td');
            }
            
            function 
    create($msg) {
                if(
    is_string($msg)) {
                    
    // accept either a STRING ...
                    
    $text Widgets::createTextNode($this -> dom$msg);
                    
                    
    Widgets::appendChild($this -> node$text);
                }
                else {
                    
    // ... or another OBJECT [ie HTML tag]
                    
    Widgets::appendChild($this -> node$msg);
                }
            }
            
            function 
    addAttribute($attr$value) {
                
    Widgets::addAttribute($this -> node$attr$value);
            }
            
            function 
    fetch() {
                return 
    $this -> node;
            }
        } 
    And for example to use this...

    PHP Code:
    include('dom-widgets.php');
        
        
    $dom domxml_new_doc('1.0');
        
    $html $dom -> create_element('html');
        
        
    $page = & new pageWidget(& $dom);
        
    $page -> createTitle('This is the title message for this page.');
        
    $page -> createCssLink('templates/css/stylesheet.css');
        
    #
        
    $table = & new tableWidget(& $dom);
        
    $table -> create(1'center''75%');
        
    $table -> addAttribute('cellspacing''1');
        
    $table -> addAttribute('cellpadding''0');
        
    $row = & new rowWidget(& $dom);
        
        
    $cell = & new cellWidget(& $dom);
        
    $cell -> addAttribute('width''50%');
        
    $cell -> addAttribute('align''center');
        
    $cell -> addAttribute('height''32');
        
    $cell -> addAttribute('valign''center');
        
    $cell -> addText('This is some sample text folks.');
        
    $row -> addRow($cell -> fetch());
        
    $cell = & new cellWidget(& $dom);
        
    $cell -> addAttribute('width''50%');
        
    $cell -> addAttribute('align''center');
        
    $cell -> addAttribute('height''32');
        
    $cell -> addAttribute('valign''center');
        
    $cell -> addText('This is some sample text folks.');
        
    $row -> addRow($cell -> fetch());
        
    $table -> addTable($row -> fetch());
        
        
    $page -> addBody($table -> fetch());
        
        
    $anchor = & new anchorWidget(& $dom);
        
    $anchor -> create('Click Me Baby, One More Time');
        
    $anchor -> addAttribute('href''http://www.mydomain.com');
        
    $anchor -> addAttribute('target''_blank');
        
    $page -> addBody($anchor -> fetch());
        
        
    $image = & new imageWidget(& $dom);
        
    $image -> create('/images/large.jpeg');
        
    $image -> addAttribute('width''512');
        
    $image -> addAttribute('height''96');
        
    $page -> addBody($image -> fetch());
        
        
    $dom -> append_child($page -> finalise($html));
        
        echo(
    $dom -> dump_mem(true)); 
    Any thoughts on how to improve this ? At the moment I need to pass an object reference; ie

    PHP Code:
    $this -> node Widgets::createElement($this -> dom'title'); 
    In this case it's
    PHP Code:
    $this -> dom 
    but is it possible just to use for example

    PHP Code:
    $this -> node Widgets::createElement('title'); 
    ?

    Thanks for any help, and again Firepages, sorry for the intrusion

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

    I think that the decorators route you are both following is the correct one as it will be a lot more flexible down the line. Have you tried automating the decorator creation?

    First a base class...
    PHP Code:
    class Wrapper {
        var 
    $_object;

        function 
    Wrapper(&$object) {
            
    $this->_object = &$object;
        }
        function &
    getWrapped() {
            return 
    $this->_object;
        }

    Now the generator...
    PHP Code:
    class Decorator {
        function 
    generate($class) {
            if (!
    class_exists($class)) {
                return 
    false;
            }
            if (
    class_exists($decorator $class 'Decorator')) {
                return 
    false;
            }
            return eval(
    Decorator::createDecoratorCode($class$decorator));
        }
        function 
    createDecoratorCode($class$decorator) {
            
    $code "class $decorator extends Wrapper {\n";
            
    $code .= "    function $decorator(&\$decorated) {\n";
            
    $code .= "        \$this->Wrapper(\$decorated);\n";
            
    $code .= "    }\n";
            foreach (
    get_class_methods($class) as $method) {
                
    $code .= Decorator::_createMethodCode($method);
            }
            
    $code .= "}\n";
            return 
    $code;
        }
        function 
    _createMethodCode($method) {
            
    $code .= "    function &$method() {\n";
            
    $code .= "        \$args = func_get_args();\n";
            
    $code .= "        \$labels = array();\n";
            
    $code .= "        for (\$i = 0; \$i < count(\$args); \$i++) {\n";
            
    $code .= "            \$labels[\$i] = '\$args[' . \$i . ']';\n";
            
    $code .= "        }\n";
            
    $code .= "        \$decorated = &\$this->getWrapped();\n";
            
    $code .= "        eval('\$ret = \$decorated->$method(' . implode(', ', \$labels) . ');');\n";
            
    $code .= "        return \$ret;\n";
            
    $code .= "    }\n";
            return 
    $code;
        }

    Ok, there is a nested eval() in there and I haven't tested it so take the code with a pinch of salt. Also it does not handle reference parameters properly, so more information would be needed about the class in this case.

    Usage would be...
    PHP Code:
    Decorator::generate('GtkWidget');

    class 
    MyGtkWidget extends GtkWidgetDecorator {
        function 
    MyGtkWidget( ... ) {
            
    $this->GtkWidgetDecorator(new GtkWidget( ... ));
            ...
        }
        ...

    This way you only write code for the methods you actually modify...
    PHP Code:
    class MyGtkWidget extends GtkWidgetDecorator {
        ...
        function 
    doStuff( ... ) {
            ...
            
    $result = &parent::doStuff( ... );
            ...
        }

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

  8. #8
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hello...

    I think that the decorators route you are both following is the correct one as it will be a lot more flexible down the line.
    Are you referring to my script I've posted ?

    Wasn't aware that I was using the Decorator Pattern...

    Still trying to find any real time to read up on patterns as I think they're important but if you say I'm using the Decorator Pattern, I'll not argue

    Thanks btw for your comments I'm looking at them just now to see what I can make of it...

  9. #9
    ********* wombat firepages's Avatar
    Join Date
    Jul 2000
    Location
    Perth Australia
    Posts
    1,717
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    aggh , as if head wasn't hurting already

    I see where you are going Lastcraft and I almost understand it
    1 problem for php-gtk in particular is that reflection does not work so well,
    eg calling get_class_methods() on a native php-gtk widget calls the entire gtkObject hierarchy of methods many of which don't all apply to say a GtkFrame , worse still calling those methods is fatal, eg $GtkNative->set_border_width($int) works on most Gtk Widgets but will die if applied to GtkFrame.

    I will have the same issue with php-gtk signals for native widgets as again they all inherit from gtkObject but not all are useable !

    That said , (and I am with DrL when it comes to painting and decorating , eg I didn't know I was) , its still very interesting and informative thankyou , and I am gonna rack my head to see if I can get a php-gtk specific implementation of the above of some kind , but as I have stated before I am an OOP muppet ('fp, why are you using aggregation ?' , fp::'wha ? I don't own a tractor ?')

    If I have missed something obvious BTW in the above please let me know , they are just my first impressions.

    DrL , please hijack away! , the more the merrier , you know I am not an XML fan , less still DOM XML but I took my first 'I HAVE to use XML' here step with this project .. the plan is eventually that you could stream say a simple form or form set from XML via a class like yours (or plain XML) and get a ready made php-gtk GUI cretated even with some simple connected signals etc , its forcing me to use strict xhtml (or valid XML) which irks me but whatever

    I tried (forever it seemed) to use serialised objects but that always got the better of me ... actually I do use serialised objects now but only after I have created it via an xml parser ~

  10. #10
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    ... to painting and decorating ...


    Not much of an DIY enthusiast myself

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

    Easy to solve. When you get the method list for the decorated class, subtract the abstract Gtk methods. Just have a version of the generator called GtkDecorator or some such.

    I agree it is 'bendy' code. If you just print the code from the methods it should make more sense. The complication is trying to pass through a variable number of arguments and so it reads it as $args and then writes some code to call it as $args[0], $args[1], etc.

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


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
  •