Page 1 of 1

Object Associations

Posted: Wed May 14, 2003 10:07 am
by luncep
I know PHP is not an OO language, however its simplicity has attracted me to building web applications using it. I am a strong believer in Object designs for modular coding and am trying to work with PHPs restrictions. However I believe I have hit a snag. When an object is associated with another object, it apparently becomes associated with a copy of that object, not the object itself. This becomes impossible to deal with cyclical references.
Example

class Organization{
var $Members;

class Members{
var $Organization;
}

$phpDevelopers = new Organization();
$joe = new Member();
$phpDevelopers->Members['Joe'] = $joe;
$joe->Organization = $phpDevelopers;

$mary = new Member();
$phpDevelopers->Members['Mary'] = $mary;
$mary->Organization = $phpDevelopers;

$sue = new Member();
$phpDevelopers->Members['Sue'] = $sue;
$sue->Organization = $phpDevelopers;

if I ask Joe, what other people are members of his organization, he would say nobody. Mary would say Joe, and Sue would be the only correct answer of Joe and Mary.

Am I correct in my assumption of the association being to a copy and is there a way around this?

Posted: Tue Feb 03, 2004 11:26 pm
by IlyaNemihin
User &$variable to pass reference.

See example:

Code: Select all

<?php

// example of OOP of PHP

class Organization&#123; 

  var $_members; 
  var $_name;

  function Organization( $name )&#123;
    $this->_name = $name;
  &#125;

  function addMember( &$member )&#123;
    $member->setOrganization( &$this );
    $this->_members&#1111;$member->getName()] = &$member;
  &#125;

  function getMemberNames()&#123;
    // return array of members
    return array_keys( $this->_members );
  &#125;

  function getName()&#123;
    return $this->_name;
  &#125;

&#125;

class Member&#123; 

  var $organization;
  var $_name;

  function Member( $name )&#123;
    $this->_name = $name;
  &#125;

  function getName()&#123;
    return $this->_name;
  &#125;

  function setOrganization( &$organization )&#123;
    $this->organization = &$organization;
  &#125;


&#125; 

$phpDevelopers = new Organization( 'phpDevelopers' ); 

$joe = new Member( 'joe' ); 
$phpDevelopers->addMember( &$joe ); 

$mary = new Member( 'mary' ); 
$phpDevelopers->addMember( &$mary ); 

$sue = new Member( 'sue' ); 
$phpDevelopers->addMember( &$sue );

// test

print 'Name: '.$joe->getName()."\n";
print 'Organizarion: '.$joe->organization->getName()."\n";
print 'Members: '.join( ', ', $joe->organization->getMemberNames() )."\n";
print "\n";

print 'Name: '.$mary->getName()."\n";
print 'Organizarion: '.$mary->organization->getName()."\n";
print 'Members: '.join( ', ', $mary->organization->getMemberNames() )."\n";
print "\n";

?>
Note, that when we add member to the organization we set reference to the organization.

Regards,
Ilya

Posted: Wed Feb 04, 2004 7:51 am
by McGruff
From eclipse readme:
- To get Java-like object behavior, ALWAYS use references when:
- Creating objects : $object =& new Object;
- Passing objects : function receiveObject(&$object) { //... }
- Returning objects: function &returnObject() { return $object; }

PHP's default behavior is to create copies, which is almost always NOT what
you really want. When some object contains a reference to a second object
and you create a copy of the first object instead of a reference, this copy
will NOT share the reference to the second object, but will hold a copy of
that object instead. This can (and will) lead to strange and undesired
behavior. To summarize:

function &getNiftyComputationResult(&$iterator))
{
$result =& new NiftyComputationResult;
for ($iterator->reset(); $iterator->isValid(); $it->next())
{
$result->add($iterator->getCurrent());
}
return $result;
}

$it =& new ArrayIterator(array(8, 5, 3, 9, 6, 1, 7, 4, 2));
$result =& getNiftyComputationResult($it);

It takes a while to get used to, but it is truly the only way to correctly
handle objects in PHP 4 ('correctly' meaning 'Java-like' in this context).
OOP works very well in php no matter what some people say. Take a look at http://www.phppatterns.com.

Incidentally, this is how you would define an interface template in php:

Code: Select all

<?php
class Thing
{
    function foo() 
    {
        die('Method not implemented<br />.' . __LINE__ . ' | ' . __FILE__);
    }

    function bar()
    {
        die('Method not implemented<br />.' . __LINE__ . ' | ' . __FILE__);
    }

}
?>

Posted: Mon May 24, 2004 7:18 pm
by phppeanuts
> ALWAYS use references when (...)

Same for arrays holding objects. And do not use forEach to run through them, it copies objects too. Use:
while (list($key) = each($objects)) {
$obj =& $objects[$key];

Posted: Mon May 24, 2004 7:21 pm
by McGruff
phppeanuts wrote:> ALWAYS use references when (...)

... and do not use forEach to run through them, it copies objects too. Use:
while (list($key) = each($objects)) {
$obj =& $objects[$key];
Or possibly an Iterator class.

Posted: Tue May 25, 2004 6:36 am
by phppeanuts
Hi McGruff,

At first sight is seems kind of overkill to me to create a class just to replace those two or three (with reset()) lines of code. But maybe there is some magic to it i am ignorant about, so i took a look at phpClasses.org (i found a reference to this thread on their forum) and found a class
Iterator. It has a function pos() method but it does NOT return a reference. Same for the at($index) method. 8O

Maybe i am biased by my Smalltalk & XP background, but foreach just seems to be "the simpelest thing that could possibly work" for simply iterating - except it does not work properly with objects in php4 :( .

Greetings,

Henk,
http://www.phpPeanuts.org.

Posted: Tue May 25, 2004 7:48 am
by McGruff
I wouldn't replace foreach with an iterator for every single loop but often a piece of code can be made more generic by using an iterator. The std example is a Table decorator which can take any kind of collection as an arg - QueryIterator, ArrayIterator, etc and prints a table. Implementation hiding is the magic.

The iterator class in your link looked a bit unfocussed although I didn't spend much time looking at it. Eclipse is what I'd recommend (returns a ref).

There is also a phppatterns take on the iterator interface. Jason's thoughts here. As you maybe know, iterators have now been added to php5.

Posted: Tue May 25, 2004 9:52 am
by McGruff
PS: forgot to mention you can use foreach to iterate through a list of objects whilst maintaining references (php4):

Code: Select all

<?php

/*
    CLASS Foo
*/
class Foo 
{
    var $state = 'ugly duckling';


    function change()
    {
        $this->state= 'beautiful swan';
    }

    function getState()
    {
        return $this->state;
    }

}
///////////////
// END CLASS //
///////////////

$foo =& new Foo;

$array = array();
$array[] =& $foo;

foreach($array as $ob)
{
    $ob->change();
}

echo $foo->getState(); // ugly duckling - copied objects

$foo =& new Foo;

$array = array();
$array[] =& $foo;

foreach(array_keys($array) as $key)
{
    $array[$key]->change();
}
echo $foo->getState(); // beautiful swan - object wasn't copied

?>