Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reference a method of container object in PHP?

Tags:

php

Given the following in PHP:

<?php
class foo {
  public $bar;
  function __construct() {
    "Foo Exists!";
  }

  function magic_bullet($id) {
    switch($id) {
    case 1:
      echo "There is no spoon! ";
    case 2:
      echo "Or is there... ";
      break;
    }
  }
}

class bar {
  function __construct() {
    echo "Bar exists";
  }
  function target($id) {
    echo "I want a magic bullet for this ID!";
  }
}

$test = new foo();
$test->bar = new bar();
$test->bar->target(42);

I'm wondering if it's possible for the 'bar' class to call the 'magic bullet' method of the 'foo' class. The 'bar' instance is contained by the 'foo' instance, but is not in a parent/child relationship with it. In actuality, I've got many various "bar" classes that "foo" has in an array, each doing something different to $id before wanting to pass it off to the "magic_bullet" function for an end result, so barring a structure change of the class relations, is it possible to access a method of a 'container' instance?

like image 956
MidnightLightning Avatar asked Aug 06 '09 17:08

MidnightLightning


2 Answers

You have to modify your code to provide a relationship. in OOP-speak, we call this aggregation.

Assuming PHP 4, and the idea of "an array of bars"

<?php

class foo {
  var $bars = array();
  function __construct() {
    "Foo Exists!";
  }

  function magic_bullet($id) {
    switch($id) {
    case 1:
      echo "There is no spoon! ";
    case 2:
      echo "Or is there... ";
      break;
    }
  }

  function addBar( &$bar )
  {
    $bar->setFoo( $this );
    $this->bars[] = &$bar;
  }
}

class bar {
  var $foo;
  function __construct() {
    echo "Bar exists";
  }

  function target($id){
    if ( isset( $this->foo ) )
    {
      echo $this->foo->magic_bullet( $id );
    } else {
      trigger_error( 'There is no foo!', E_USER_ERROR );
    }
  }
  function setFoo( &$foo )
  {
    $this->foo = &$foo;
  }
}

$test = new foo();
$bar1 = new bar();
$bar2 = new bar();

$test->addBar( $bar1 );
$test->addBar( $bar2 );

$bar1->target( 1 );
$bar1->target( 2 );
like image 141
Peter Bailey Avatar answered Sep 24 '22 19:09

Peter Bailey


No, it's not possible, as there is no relationship defined.

I'd suggest that instead of setting the $test->bar property directly, you use a setter, and you can establish a relationship that way. You'll also need to add a container property to the bar class. Inside class foo:

function setBar(bar $bar)
{
    $bar->container = $this;
    $this->bar = $bar;
}

That sets up a relationship between the objects. Now change the bar::target($id) function to:

function target($id)
{
    $this->container->magic_bullet($id);
}

You should be able to do this now:

$test = new foo();
$bar = new bar();
$test->setBar($bar);
$test->bar->target(42);
like image 31
zombat Avatar answered Sep 25 '22 19:09

zombat