OOP Stumbling Block

admin

Administrator
Staff member
I have what I consider an elementary OOP question, but everything I read about OOP and PHP leaves the thing I want to know unsaid or buried so deep I can't get at it. In fact, not understanding this probably simple solution has kept me stuck at the procedural programming level for years. Let me present a hypothetical project that illustrates my dilemma.

Suppose I create a class of 1000 planetary probe objects and a class of 100 planet objects (properties and methods I understand). Each probe object has a unique name, as does each planet object. I want the planet objects to launch at intervals, and I want the planet objects to move in orbits.

MY QUESTION: Without hardwiring the code, how do I dynamically reference 1000 individual probe objects to launch them? Without hardwiring the code, how do I dynamically reference the 100 planets to move them?

With arrays instead of objects, no problem. I write one loop that launches probe[0] then probe[1] and so on. I write another, more complex loop, that moves the planets--planet[0], planet[1], etc.

Do I solve this problem by adding each object to an array as I create it? Does the Class have an internal, hidden array of the objects constructed that lets me access them without making my own array? Just how do OOP programmers deal with multiple objects dynamically? If anyone could answer simply or point towards a site with examples that answer my question, I would be much obliged.I think I'd probably create a motion class that would include as one of its class variables an array of objects to be moved. It would include a method for adding objects to that array (and one to delete them if needed) and a method to loop through all those object to move them.I tried that this morning, but I had to stop when I got to this syntax issue.

I was going to put a method call inside the constructor that would add the object being instantiated to an array of objects. But exactly how do I phrase the method call and the method. Is this right ...

Inside the constructor ...

$this.addToArray($this);

And the method ...

function addToArray($obj)
{
$probes[$cProbes++] = $obj;
}

Afterwards, I would use the array element as the object itself ...

$probe117.flyToMars(); = $probes[116].flyToMars();


The problem I'm worried about is sending the name of the object into the array instead of the object itself. The syntax above wouldn't work if the element were just a name and not the object.Firstly, remember that PHP uses the "->" as the object hierarchy operator, not a "." as in Java/JavaScript.

I would just do:

class Motion
{
private $planets = array();
private $probes = array();

public addPlanet($obj)
{
if(is_a($obj, 'Planet')) // change 'Planet' to correct class name
{
$this->planets[] = $obj;
return(TRUE);
}
else
{
// throw exception or raise error, then:
return(FALSE);
}
}

public addProbe($obj)
{
// same logic as addPlanet()
}
}

$planet1 = new Planet();
$mover = new Motion();
$mover->addPlanet($planet1);Thank you, NogDog, I will study your code.

I assume I've created a Planet Class and a Probe class elsewhere and the Motion Class exists solely to add the objects from these classes to arrays I can manipulate?

P.S. If I repost in this thread, the classes and objects may change. The real problem I'm tackling is creating virtual Middle School Students that will move through a universe of Courses and schedule themselves. Essentially, it's the same problem as probes and planets, but students and courses are SO boring compared to probes and planets.This is an occasion where interfaces can really shine. To extend on NogDog's example, all we really care about is that the object being added can move in some way. So we can isolate that behaviour using an interface.

interface IMovable
{
public function move( $x, $y );
}
class Planet extends Spherical implements IMovable
{
public function move( $x, $y )
{
$this->orbit( $x, $y );
}
}
class Probe extends ManMade implements IMovable
{
public function move( $x, $y )
{
$this->thrust( $x, $y );
}
}

Now all the Motion class cares about is that the object implements the IMovable interface. It's useful to use an interface rather than an abstract class, because we are only requiring that a particular behaviour exists (move(), in this case). This leaves our 1 shot of inheritance to be used for something more specific.

class Motion
{
private $moveables = array();

public function add( IMovable $obj )
{
$this->moveables[] = $obj;
return true;
}
public function move( $x, $y )
{
foreach( $this->moveables as $obj )
{
$obj->move( $x, $y );
}
}
}
$motion = new Motion;
$motion->add( new Probe );
$motion->add( new Planet );
$motion->move( 1, 2 );

Having said all of this, it is unlikely that you would want to work this way in your real-life problem. If you are envisioning a website application to manage courses and students you will only ever be dealing with a few instances of objects. HTTP being a stateless protocol tends to mean not much is kept in memory at any given time, rather things are loaded from and written to a database as and when they are needed.Thank you, Shrike. I've read about interfaces, but even in my past C++ and Java coursework I've never actually written one.

Though my courses aren't actually in orbit, they will be reordering themselves constantly to ensure even distribution of students. They will also be regulating their own gender and racial balance to match the school's gender and racial balance.

I'll be studying your suggestions also.

P.S. Student and course info are drawn from a MySQL database and the pairings of students with courses are written back to MySQL. The goal is to completely automate the scheduling for a school over-night and then have guidance counselors tweak the product till it's usable.NogDog,

I think I absorbed and applied the Motion Class principles you laid out. I renamed the class Matchmaker because its eventual goal is to match a Student to an available Seat in a course. Thus ...

$mover->addPlanet($planet1) becomes $matchmaker->addStudent($s1)


Along the way, I came up with a question.

BACKGROUND: I have a main.php file that uses a series of include statements to load the various pieces of the program. The Student piece, for instance, loads the Student class definition file. Then it loads a file that reads information from a MySQL table to dynamically create an instantiation string for each student object. An eval() statement then executes the string.

I tried loading

$matchmaker->addStudent($this)

to the Student class constructor. That seemed like the perfect place to put it, but doing so generated an error message. I put it in the file that dynamically created the instantiation statement and it worked.

QUESTION: Is there a way to put the equivalent of $matchmaker->addStudent($this) into the Student constructor statement, or is that a completely wrongheaded approach to the problem?

JKAre you passing $matchmaker to the Student constructor?

class Student
{
function __construct($matchMaker)
{
$matchmaker->addStudent($this);
}
}

That does couple the student and matchmake class fairly closely which is generally not a good thing. Probably be better to add the student to the matchmaker outside of the student constructor.
 
Back
Top