Page 3 of 4

Posted: Sun Mar 11, 2007 10:53 pm
by feyd
arborint wrote:But your constructor is not really returning anything -- new is.
Are you agreeing with me? Image

-------

Here's another potential example Kieran (unrelated to my above comments.)

Code: Select all

<?php

class foo
{
	private $args;
	
	protected function __construct()
	{
		// do some stuff
		
		list( $this->args ) = func_get_args();
	}
	
	public static function makeInstance()
	{
		return new foo( func_get_args() );
	}
	
	public function __toString()
	{
		return 'hi: ' . implode( ', ', $this->args );
	}
	
	public function doStuff()
	{
		echo 'I\'m inside a method! (' . __FUNCTION__ . '())' . PHP_EOL;
		
		return $this;
	}
}

function foo()
{
	$args = func_get_args();
	return call_user_func_array( array( 'foo', 'makeInstance' ), $args);
}

$foo = foo('a','b','c')->doStuff();

echo $foo;

?>
outputs

Code: Select all

I'm inside a method! (doStuff())
hi: a, b, c

Posted: Mon Mar 12, 2007 1:30 am
by Christopher
feyd wrote:Are you agreeing with me? Image
Well, I almost always agree with you. :) Sorry, I meant to quote Kieran. I edited my post.

Posted: Mon Mar 12, 2007 10:27 am
by Kieran Huggins
I think I've got it now... I was using return as flow control structure and I shouldn't have been -- thanks guys!

Posted: Tue Mar 13, 2007 6:08 am
by Ollie Saunders
return is a great flow control structure!
just use it without a parameter when inside a constructor otherwise you are going to confuse everyone... like you just did

Code: Select all

// this is perfectly legit in my mind:
public function __construct($a)
{
    if ($a == 4) {
        return;
    }
    // do stuff
}

Posted: Thu Mar 15, 2007 12:15 pm
by Kieran Huggins
ok - up for comments is the kQuery class itself (partial, but at least working):

I'm developing the data model base class that supports the expected kQuery interface (as well as auto-saving) now.

Comments? Suggestions?

Code: Select all

class kQuery{

/*
METHODS SO FAR:

add() // adds objects that match somehow

attr('name') // returns the value for the "name" attribute in the first object

attr('name','val') // sets 'name' to 'val' for ALL matched objects

size() // returns the number of objects

eq() // shrinks the kQuery object to the numbered object

gt() // shrinks the kQuery object to the numbered object UP

lt() // shrinks the kQuery object UP TO the numbered object

get() // returns a new kQuery object with the object at that position

end() // will break out of the last get() scope change

each('func_name'); // executes a function with the object as an argument

each('echo $this->value'); // creates a lambda function and executes it

each(create_function('$this','echo "this is a lambda function"'));  // executes the lambda function


USAGE:

$bob = $k('dataType #id')->attr('name','bob')->attr('age','old');

// this could have been chained above as well... but whatever.
$bob->add('dataType #id2')->attr('group','seniors')->get(1)->attr('name','frank')->end()->attr('favorite food','tapioca');

// caching in the $bob variable is just a handy tool for future reference, but not necessary. 
$k('dataType #id','dataType #id2')->attr('group','old fogeys')->each(create_function('','if($this->age <= 60){$this->age = "65"}'))->each('$this->age++;');

(check out those lambda functions in action!)
*/

	private $_ = array();
	private $__, $__parent;

	function __construct(){
		// no arguments? return a blank kQuery object
		if(func_num_args()==0) return $this;

		$a = func_get_args();

		call_user_func_array(array($this,'add'),$a);
		
		return $this;
	}

	public function add(){
		$args = func_get_args();
		
		foreach($args as $a){
			// object (wrapping the object)
			if(is_object($a)){
				$this->_[] = $a;
			}

			// string (query)
			if(is_string($a)){
				// parse the query 
				call_user_func(array($this,'query'),$a);
			}
		}

		return $this;
	}

	public function attr(){
		if( func_num_args()==1 ) {
			$k = func_get_arg(0);
			return $this->_[0]->$k;
		}else if( func_num_args()==2 ){
			$k = func_get_arg(0);
			$v = func_get_arg(1);
			foreach((array)$this->_ as $o){
				$o->$k = $v;
			}
			return $this;
		}
	}

	public function size(){
		return sizeof($this->_);
	}

	public function eq(){
		$pos = func_get_arg(0);
		if(!is_numeric($pos)) return false;
		if( isset($this->_[$pos]) ) $this->_ = array($this->_[$pos]);
		return $this;
	}

	public function gt(){
		$pos = func_get_arg(0);
		if(!is_numeric($pos)) return false;
		if( isset($this->_[$pos]) ) $this->_ = array_slice($this->_,$pos);
		return $this;
	}

	public function lt(){
		$pos = func_get_arg(0);
		if(!is_numeric($pos)) return false;
		if( isset($this->_[$pos]) ) $this->_ = array_slice($this->_,0,$pos+1);
		return $this;
	}

	public function get(){ // must be non-destructive
		$pos = func_get_arg(0);
		if(!is_numeric($pos)) return false;
		if( isset($this->_[$pos]) ) $this->__ = new kQuery($this->_[$pos]);

		$this->__->__parent = &$this;

		return $this->__;
	}

	public function end(){
		if($this->__parent) return $this->__parent;
		return false;
	}


	public function each(){ // object is passed as the only argument
		$args = func_get_args();
		foreach((array)$this->_ as $o){
			echo '<br/>';
			foreach($args as $a){
				// if it's a lambda function
				if(strpos($a,'lambda_')=='1'){
					$a($o);
					continue;
				}
				// if it's a string of a function (ends in ; or } )
				$a = trim($a);
				if(strpos($a,';')==strlen($a)-1 || strpos($a,'}')==strlen($a)-1){
					$a = create_function('$this',$a);
					$a($o);
					continue;
				}
				
				// must be the name of a function
				call_user_func($a,$o);
			}
		}
	}

	/* private methods */

	private function query(){

		$a = func_get_arg(0);

		preg_match('#(\w+)\s?(?:\#(\w+))?\s?(?:(\w*)=?(\w*))?#i',$a,$q);
		//outputs:
		//    [0] => full string
		//    [1] => ThingType
		//    [2] => id			(if any)
		//    [3] => attr		(if any)
		//    [4] => val		(if any)

		if(empty($q[1])) dier(__FILE__.'->'.__LINE__."\n",$q);

		// return a blank object of type ThingType
		if(empty($q[2]) && empty($q[3]) && empty($q[4])){
			$this->_[] = new $q[1];
		}

		// get by ID
		if(!empty($q[2]) && empty($q[3]) && empty($q[4])){
			$this->_[] = new $q[1]($q[2]);
		}

		// STILL TO IMPLEMENT (as I need them): 
		//
		// get by attibute
		// get by value
		// get by attibute=value
		// get by attibute!=value
		// get by attibute<=value... (and others)

	}

}
$k = create_function('','$args=func_get_args(); return call_user_func_array(array(new kQuery(),"__construct"),$args);');
EDITED to fix the call_user_func() error in the ->add() method...

Posted: Thu Mar 15, 2007 12:21 pm
by Ollie Saunders
Please change your constructor to this...

Code: Select all

function __construct(){
        if(func_num_args()) {
            $args = func_get_args();
            call_user_func_array(array($this,'add'),$args);
        }
}
...or we are going to have to have the same discussion all over again. :)

OK I'm going to carry on reading your code now...back soon.

Posted: Thu Mar 15, 2007 12:31 pm
by Ollie Saunders
kQuery::add() wrote:

Code: Select all

if(is_string($a)){
    // parse the query
    call_user_func_array(array($this,'query'),$a);
}
You've just proven that $a is a string but you are using it as if it is an array.

Code: Select all

private function query(){
    $a = func_get_arg(0);
why not

Code: Select all

private function query($a){
same applies to several other methods.

I'll try and run this when I get home because its pretty intriguing. Also the code is quite confusing:

Code: Select all

private $_ = array();
private $__, $__parent;
What exactly are those storing? I actually loled at this line

Code: Select all

$this->__->__parent = &$this;

Posted: Thu Mar 15, 2007 1:03 pm
by Kieran Huggins
ole wrote:Please change your constructor to this...

Code: Select all

function __construct(){
        if(func_num_args()) {
            $args = func_get_args();
            call_user_func_array(array($this,'add'),$args);
        }
}
...or we are going to have to have the same discussion all over again. :)

OK I'm going to carry on reading your code now...back soon.
translation: "am I gonna have to come down there and slap you silly?" :rofl:

I need to return the object to make it chainable, and it doesn't seem to break anything.. do you have a chainable alternative in mind?
ole wrote:
kQuery::add() wrote:

Code: Select all

if(is_string($a)){
    // parse the query
    call_user_func_array(array($this,'query'),$a);
}
You've just proven that $a is a string but you are using it as if it is an array.
oops... changed to the regular call_user_func();
ole wrote:

Code: Select all

private function query(){
    $a = func_get_arg(0);
why not

Code: Select all

private function query($a){
same applies to several other methods.
Just getting into the habit of accepting variable numbers of arguments.
ole wrote:I'll try and run this when I get home because its pretty intriguing. Also the code is quite confusing:

Code: Select all

private $_ = array();
private $__, $__parent;
What exactly are those storing? I actually loled at this line

Code: Select all

$this->__->__parent = &$this;
yeah.... they are a bit ambiguous. Just made the vars shorter, but I should have expanded them:
$_ is an array of matching data objects
$__ is a single object matched by a non-destructive method ( like get() )
$__parent is the reference to the parent kQuery object from within a non-destructively matched data object

Thanks ole -- your input is greatly appreciated! ;-)

Posted: Thu Mar 15, 2007 2:03 pm
by Ollie Saunders
Thanks ole -- your input is greatly appreciated!
I might have been a bit overly critical actually. I dunno. I was a bit annoyed with someone when I wrote that.
I need to return the object to make it chainable, and it doesn't seem to break anything.. do you have a chainable alternative in mind?
Err, OK I take that back. I would then recommend explicitly commenting the reasoning behind it - docblocks on top of each method would be a good idea in general.

Posted: Thu Mar 15, 2007 2:16 pm
by Kieran Huggins
No worries 8)

I've always been terrible about structured commenting - I will start doing that now!

Posted: Tue Apr 17, 2007 5:43 pm
by Luke
any news on this? Seems really cool.

Posted: Tue Apr 17, 2007 9:15 pm
by Kieran Huggins
hmmm.... let's see.

I've broken down the kQuery conceptually into two pieces: the selector/container (the kQuery) and the data object parent (kDO).

Data objects are loaded into the $_SESSION['kDO'] array and then passed around by reference to save memory/duplication as well as preserve "congruity?".

The last session I spent working on it I was wrestling with how to link data objects together, and how to avoid auto-loading the whole chain every time an object is loaded. My general plan was to load objects when the first get/set/method is run on them, thereby not loading unneeded objects.

I still don't feel completely satisfied with my solution, but as I work it out in my spare time (which has been rather limited lately :-() it's all coming together!

Posted: Tue Apr 17, 2007 9:26 pm
by John Cartwright
Keep it it up! I know I am patiently awaiting some results :D

Posted: Wed Apr 18, 2007 10:31 am
by RobertGonzalez
I am rather interested in seeing this as well.

Posted: Wed Apr 18, 2007 4:15 pm
by Kieran Huggins
wow - I sure hope I don't disappoint you guys with the results! Thanks for the encouragement :-)