SitePoint Sponsor

User Tag List

Results 1 to 13 of 13
  1. #1
    Resident OCD goofball! bronze trophy Serenarules's Avatar
    Join Date
    Dec 2002
    Posts
    1,911
    Mentioned
    26 Post(s)
    Tagged
    0 Thread(s)

    Exclamation Classes with reference returning functions.

    Consider the following classes...

    PHP Code:
    class main {
     
    var 
    $_sub;
     
    function 
    main() {
    $this->_sub = new sub();
    // end func
     
    function &sub() {
    return 
    $this->_sub;
    // end func
     
    } / end class
     
    class 
    sub {
     
    var 
    $_end;
     
    function 
    sub() {
    $this->_end = new end();
    // end func
     
    function &end() {
    return 
    $this->_end;
    // end func
     
    } / end class
     
    class 
    end {
     
    function 
    wrap($input) {
    return 
    'BEGIN-WRAP: ' $input ' :END-WRAP';
    // end func
     
    } / end class 
    ...and implemented it like this...

    PHP Code:
    $m = new main();
    $s $m->sub();
    $e $s->end();
    $f $e-wrap("some text to wrap"); 
    ...but is there a way I can do something like this instead...

    PHP Code:
    $m = new main();
    $f $m->sub()->end()->wrap("some text to wrap"); 
    ...in VB fashion?

    I want to create a set of classes where some are item classes and some are collection classes, and all are contained within a top levl class much like the following...

    $value = $records->itemByID($id)->fields()->itemByName($name);

  2. #2
    eschew sesquipedalians silver trophy sweatje's Avatar
    Join Date
    Jun 2003
    Location
    Iowa, USA
    Posts
    3,749
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    PHP5 allows this syntax, not PHP4
    Jason Sweat ZCE - jsweat_php@yahoo.com
    Book: PHP Patterns
    Good Stuff: SimpleTest PHPUnit FireFox ADOdb YUI
    Detestable (adjective): software that isn't testable.

  3. #3
    Resident OCD goofball! bronze trophy Serenarules's Avatar
    Join Date
    Dec 2002
    Posts
    1,911
    Mentioned
    26 Post(s)
    Tagged
    0 Thread(s)
    Crud...debian stable...all I have is 4. :\

  4. #4
    eschew sesquipedalians silver trophy sweatje's Avatar
    Join Date
    Jun 2003
    Location
    Iowa, USA
    Posts
    3,749
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Time to upgrade to Gentoo

  5. #5
    SitePoint Wizard
    Join Date
    Aug 2004
    Location
    California
    Posts
    1,672
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Much easier, add the following to your /etc/apt/sources.list:

    deb http://packages.dotdeb.org ./

    Then:

    apt-get install php5

    They have a bunch of other packages for PHP5 on Debian stable like CURL, GD, mysqli, etc. Go to http://www.dotdeb.org for more info.

    PS "upgrade"?

  6. #6
    eschew sesquipedalians silver trophy sweatje's Avatar
    Join Date
    Jun 2003
    Location
    Iowa, USA
    Posts
    3,749
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by arborint
    PS "upgrade"?
    Just wanted to start a distro riot Slow day

  7. #7
    Resident OCD goofball! bronze trophy Serenarules's Avatar
    Join Date
    Dec 2002
    Posts
    1,911
    Mentioned
    26 Post(s)
    Tagged
    0 Thread(s)
    Here's my php4 solution, which I just worked out. It's not elegent but it works.

    [inline.php]
    PHP Code:
    <?php
     
    function inline_eval(&$obj$code) {
     
    // split the code
     
    $lines explode('->'$code);
     
    // get the last call - this should return a mixed var
     
    $last array_pop($lines);
     
    // set the first element
     
    $result =& $obj;
     
    // process remaining calls - these should all return object references
     
    if (count($lines)) {
     
    for (
    $line 0$line count($lines); $line++) {
     
    eval(
    "\$result =& \$result->$lines[$line];");
     
    }
     
    }
     
    // process last call
     
    eval("\$result = \$result->$last;");
     
    // return result - should contain mixed value
     
    return $result;
     
    }
     
    ?>
    [usage.php]
    PHP Code:
    <?php
     
    include('inline.php');
     
    class 
    First {
     
    var 
    $_second null;
     
    function &
    Second() {
     
    if (
    is_null($this->_second)) { $this->_second = new Second(); }
     
    return 
    $this->_second;
     
    }
     
    }
     
    class 
    Second {
     
    var 
    $_third null;
     
    function &
    Third() {
     
    if (
    is_null($this->_third)) { $this->_third = new Third(); }
     
    return 
    $this->_third;
     
    }
     
    }
     
    class 
    Third {
     
    function 
    Format($input) {
     
    return 
    "<b><i>$input</i></b>";
     
    }
     
    }
     
    $input 'Hello world!';
     
    $first = new First();
     
    echo 
    inline_eval($first"Second()->Third()->Format('$input')");
     
    unset(
    $first);
     
    ?>
    As you can see, one would pass in the first obj by reference and the function call chain in as a string. All calls except the last are expected to return an object reference. The last call should return a mixed value. Take care to properly enclose function args with either ' or " depending on how you quoted the entire string.

    Note: I did not test this using a single call as there is no need, therefore, no error cheching exists in this sample.


  8. #8
    eschew sesquipedalians silver trophy sweatje's Avatar
    Join Date
    Jun 2003
    Location
    Iowa, USA
    Posts
    3,749
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Neat idea, how about this implementation:

    PHP Code:
    class chainOne { function &makeTwo() { return new chainTwo; }}
    class 
    chainTwo { function &makeThree() { return new chainThree; }}
    class 
    chainThree { function &makeTest() { return new chainTest; }}
    class 
    chainTest { function &doIt() { return 'made it!'; }}

    function &
    chain(&$obj$call) {
        return 
    call_chain($objexplode('->',$call));
    }
    function &
    call_chain(&$obj$stack) {
        if (
    $stack) {
            eval(
    '$new_obj =& $obj->'.array_shift($stack).';');
            return 
    call_chain($new_obj$stack);
        } else {
            return 
    $obj;
        }
    }

    $one =& new chainOne;
    echo 
    chain($one'makeTwo()->makeThree()->makeTest()->doIt()'); 

  9. #9
    Resident OCD goofball! bronze trophy Serenarules's Avatar
    Join Date
    Dec 2002
    Posts
    1,911
    Mentioned
    26 Post(s)
    Tagged
    0 Thread(s)
    Hm, I didn't test your code, though I did copy it to Quanta and looked at it. I'm not sure it would work for my scenario since it creates new instances each time. Also, the depth of the chaining should be veriable. It isn't always three levels. For instance, let's say I have the following classes:

    clsItems [collection class]
    - add(&$item)
    - count
    - item($index)
    - remove($index)

    clsItem [single item]
    - properties
    - items [subitems of this item]

    clsProperties [collection class]
    - add(&$item)
    - count
    - item($index)
    - remove($index)

    clsProperty [single item]
    - name
    - value

    :where the final hierarchy could by any number of levels deep, I need to be able to not only call functions, but get/set values and have them persist. Therefore, we cannot be creating new instances of items.

    EX:
    [php]
    $top = new clsItems():

    //add a few items and properties, say from my family tree...

    inline_eval($top, "item(2)->item(0)->item(1)->item(4)->properties()->item(2)->value('the new value')");

    function value() uses func_get_args to see if a new value is to be stored or simply return the existing one. It ignores all but the first arg, if any.

  10. #10
    eschew sesquipedalians silver trophy sweatje's Avatar
    Join Date
    Jun 2003
    Location
    Iowa, USA
    Posts
    3,749
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    My code uses recursion to process the number of calls, so it can do any arbitrary depth of calls. Also, you can pass any number of either static and/or global arguments. Here is another example of classes/calls (the functions do not need to change from what I posted earlier):
    PHP Code:
    class chainOne { function &makeTwo() { return new chainTwo; }}
    class 
    chainTwo { function &makeThree($a,$b) { return new chainThree($b); }}
    class 
    chainThree { var $x; function chainThree($x) { $this->$x; }
    function &
    makeTest() { return new chainTest($this->x); }}
    class 
    chainTest { var $y; function chainTest($y) { $this->$y; }
    function &
    doIt($z) { return array('made it!',$this->y,$z); }}

    $GLOBALS['foo'] = 'baz';
    $one =& new chainOne;
    var_dumpchain($one'makeTwo()->makeThree(55,"bar")->makeTest()->doIt($GLOBALS["foo"])')); 
    this produces:
    PHP Code:
    array(3) {
      [
    0]=>
      
    string(8"made it!"
      
    [1]=>
      
    string(3"bar"
      
    [2]=>
      
    string(3"baz"

    where the "bar" value in the array came from the second argument passed to makeThree(), and the "baz" value in the array came from the global variable specified in the call chain.

    HTH

  11. #11
    Resident OCD goofball! bronze trophy Serenarules's Avatar
    Join Date
    Dec 2002
    Posts
    1,911
    Mentioned
    26 Post(s)
    Tagged
    0 Thread(s)
    Ok, what threw me off is that some functions return a non-object (string, number, etc) so I erroneously made the assumption that to return those values in the same fashion as an object reference would not work as expected. I took your sample and applied a more relistic, though still an example, application and it works.

    PHP Code:
    <?php
     
    /****************************/
     
    /**** chaining functions ****/
     
    /****************************/
     
    function &chain(&$obj$call) {
     
    return 
    call_chain($objexplode('->',$call));
     
    }
     
    function &
    call_chain(&$obj$stack) {
     
    if (
    $stack) {
     
    eval(
    '$new_obj =& $obj->'.array_shift($stack).';');
     
    return 
    call_chain($new_obj$stack);
     
    } else { 
     
    return 
    $obj
     

     

     
    /***************************/
     
    /**** class definitions ****/
     
    /***************************/
     
    class clsItem {
     
    var 
    $_items;
     
    var 
    $_name;
     
    var 
    $_value;
     
    function 
    clsItem($name$value) {
     
    $this->_items null;
     
    $this->_name $name;
     
    $this->_value $value;
     
    }
     
    function &
    Items() {
     
    if (!isset(
    $this->_items)) {
     
    $this->_items =& new clsItems();
     
    }
     
    return 
    $this->_items;
     
    }
     
    function 
    Name() {
     
    $args func_get_args();
     
    if (
    $args) { $this->_name $args[0];} else { return $this->_name; }
     
    }
     
    function 
    Value() {
     
    $args func_get_args();
     
    if (
    $args) { $this->_value $args[0];} else { return $this->_value; }
     
    }
     

     
    class 
    clsItems {
     
    var 
    $_items;
     
    function 
    clsItems() {
     
    $this->_items = array();
     
    }
     
    function &
    Add($name$value) {
     
    $item = new clsItem($name$value);
     
    $this->_items[] =& $item;
     
    return 
    $item;
     
    }
     
    function 
    Count() {
     
    return 
    count($this->_items);
     
    }
     
    function &
    Item($index) {
     
    if (isset(
    $this->_items[$index])) {
     
    return 
    $this->_items[$index];
     
    }
     
    }
     
    function 
    Remove() {
     
    if (isset(
    $this->_items[$index])) {
     
    unset(
    $this->_items[$index]);
     
    }
     
    }
     

     
    /**********************/
     
    /**** main program ****/
     
    /**********************/
     
    $out = array();
     
    $top =& new clsItem(""""); // stupid I know, but it's only a test...
     
    $out[] = chain($top'Items()->Add("HairColor", "Brown")->Value()'); 
     
    chain($top'Items()->Item(0)->Value("Blonde")'); 
     
    $out[] = chain($top'Items()->Item(0)->Value()'); 
     
    echo 
    implode('<br><br>'$out);
     
    ?>

  12. #12
    Resident OCD goofball! bronze trophy Serenarules's Avatar
    Join Date
    Dec 2002
    Posts
    1,911
    Mentioned
    26 Post(s)
    Tagged
    0 Thread(s)
    WHOA!!! I took the advice and got the dotdeb packaging of php5, a few add-ons and mysql. What a difference!!! I love the new language, it's more VB-like now and suddenly I find I can relate to PHP much better. Things I like:

    inline dereferences (what this thread was about)
    __construct()
    __destruct()
    __get()
    __set()
    protected
    private
    static

    :and much more! If you are reading this and haven't taken a look at PHP5, please read through this ZEND synopsis of the major changes.

    http://www.zend.com/php5/articles/en...s.php#Heading3

  13. #13
    SitePoint Wizard
    Join Date
    Aug 2004
    Location
    California
    Posts
    1,672
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Just wanted to start a distro riot Slow day
    Go Debian!

    Happy Holidays!


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
  •