0

I'm quite sure this isn't possible but I'm really hoping its gonna be possible.

i want to call my models in this way for instance

$getAll = models\company::getInstance()->getAll("ID < 4")

which is basicaly just

class company extends _ {
private static $instance;
function __construct() {
    parent::__construct();
}
public static function getInstance(){
    if ( is_null( self::$instance ) ) {
        self::$instance = new self();
    }
    return self::$instance;
}
function getAll($where = "") {
    // yada yada
    $this->return = $return;
    return $this;
}

at the moment i have to add a variable $this->return = $return; inside there and then later on call $getAll = models\company::getInstance()->getAll("ID < 4")->show();

function show(){
    return $this->return;
}

the idea is so that i can for instance do a $getAll = models\company::getInstance()->getAll("ID < 4")->format()->show();

so the question. is there a way to do it without show() on the end?

Ideally i want $getAll = models\company::getInstance()->getAll("ID < 4") to output the array and if i do $getAll = models\company::getInstance()->getAll("ID < 4")->format() for it to take the array from getAll() and do stuff and output the result. just seems cleaner than having to put show() on everything

please don't crucify me for bad practices. thanks in advance

Alma Do
  • 37,009
  • 9
  • 76
  • 105
WilliamStam
  • 254
  • 2
  • 13
  • 4
    This barely makes sense. By this you're lying to the one who's using your code as it is expected to get same object in return (chaining), but in fact it does manipulation with collection structure. Use explicit collection methods instead. This will be strict, type-hint-able, flexible and, in the very end, just more readable. – Alma Do Apr 24 '15 at 09:53
  • 1
    I really would want to crucify you for bad practices! ;) – Yoshi Apr 24 '15 at 10:04
  • @AlmaDo mind explaining that a bit more? not sure im following? basicaly i wanted to have a system where i can chain if theres more to do like call ->get("1")->remove() but if i just call get("1") it returns the data for it – WilliamStam Apr 24 '15 at 11:08

3 Answers3

0

Somehow you must "flag" the last call, a quick and dirty solution

class confusing {
private static $instance;

function __construct() {
    $this->return = 'nothing';
}

public static function getInstance() {
    if (is_null(self::$instance)) {
        self::$instance = new self();
    }
    return self::$instance;
}

function getAll($where = "") {
    $this->return = 'getAll'.$where;
    return $this;
}

function format() {
    $this->return = strtoupper($this->return);
    return $this;
}

function __call($name,$args) {
    $rthis = true;
    if ( 'last_'==substr($name,0,5) ) {
        $toCall = substr($name,5);
        $rthis = false;
    }
    else {
        $toCall = $name;
    }
    call_user_func_array([$this,$toCall],$args);
    return $rthis?$this:$this->return;
}
}

$x = confusing::getInstance()->getAll('x')->last_format();
$y = confusing::getInstance()->last_getAll('y');
$z = confusing::getInstance()->getAll('z');

var_export($x);
var_export($y);
var_export($z);

Or create a wrapper which outboxes

function toResult($x) {
  return is_object($x)?$x->show():$x;
}

$getAll = toResult(models\company::getInstance()->getAll("ID <4")->format());

Anyhow the called method never will know about the chain countinues or not.

cske
  • 2,233
  • 4
  • 26
  • 24
  • " the called method never will know about the chain countinues or not." was hoping i was wrong with this... i thought something like this :/ marking yours as the answer. that __call thing seems like the best idea. but i think im just going to get used to using ->show() to output anything. – WilliamStam Apr 24 '15 at 11:03
  • This is not the only way. Implementing ArrayAccess and Countable will get you what you want. See my answer below. – xCander Apr 24 '15 at 14:13
0

bottom line. its not possible.

in my case im going to keep all my methods chainable except for a ->show() which would then return the "result"

so even if i do something like users->get("1")->remove() it wont return any message but it will perform the action. users->get("1")->remove()->show() will output "User successfully removed"

previously i never bothered with chaining things but it gets frustrating fast. chaining definately does seem to help. starting a new big project and trying to do it "better" from the start

WilliamStam
  • 254
  • 2
  • 13
  • It is possible to achieve what you asked for in your question. See my answer above. Chaining methods is by the way no holy grale. Over use can lead to breaking of the law of demeter. – xCander Apr 24 '15 at 14:20
0

This is absolutely possible! What you need to do is to create a class representing a ResultSet, that can both be used as an ordinary array (by implementing the interfaces ArrayAccess, Iterator and Countable) and as an object.

Example

class ResultSet implements ArrayAccess, Countable, Iterator {

    private $data = array();
    private $position = 0;

    public function __construct(array $data=array())
    {
        $this->data = $data;
    }

    /* * Implement methods of the Countable interface * */

    public function count()
    {
        return count($this->data);
    }

    /* * Implement methods of the ArrayAccess interface * */

    public function offsetExists($offset)
    {
        return isset($this->data[$offset]);
    }

    public function offsetGet($offset)
    {
        return $this->data[$offset];
    }

    public function offsetSet($offset, $value)
    {
        $this->data[$offset] = $value;
    }

    public function offsetUnset($offset)
    {
        if( $this->offsetExists($offset) )
            unset($this->data[$offset]);
    }

    /* * Implement methods of the Iterator interface * */

    function rewind() 
    {
        $this->position = 0;
    }

    function current() 
    {
        return $this->data[$this->position];
    }

    function key()
    {
        var_dump(__METHOD__);
        return $this->position;
    }

    function next()
    {
        ++$this->position;
    }

    function valid()
    {
        return isset($this->data[$this->position]);
    }

    /* * Implementation of ResultSet specific methods  * */

    public function show()
    {
        //....
    }

    /**
     * @param $in
     * @return ResultSet
     */
    public function format($in)
    {
        // do the stuff
        return $this;
    }

}

This implementation would allow a call like ->getAll('...')->format()->show(); and at the same time allow the programmer to treat the output of getAll() as an array.

xCander
  • 1,338
  • 8
  • 16
  • seems incomplete, please show concrate usage. for array access `[]` is required, but with `Iterable` ... maybe – cske Apr 24 '15 at 14:18
  • Ah yes, that is true. It should also implement Iterable ... (fixed) – xCander Apr 24 '15 at 14:21
  • Still no sample how you use it :(, countable is irrelevant – cske Apr 24 '15 at 18:12
  • If your API states that a certain method returns an array one would expect that you could count the number of elements in that array. For what reason do you find Countable irrelevant? – xCander Apr 24 '15 at 20:19
  • thanks for the answer.. will check it out on tuesday. :D (been a looooong week, NEED the weekend off lols) – WilliamStam Apr 26 '15 at 15:41