(How) should I use object references?
Consider an example:
An application library that handles company's staff. Staff details are stored in a CSV file (please, do not judge this, as this is only used as an example).
Classes handling the staff info are (code very simplified just to give you the picture):class St开发者_运维问答aff {
/* array containing all Staff_Emplyee objects naturally (number) indexed */
public $employees;
/* array containing all Staff_Employee objects $name indexed */
public $employees_names;
/* array containing all Staff_Team objects naturally indexed */
public $teams;
/* array containing all Staff_Team objects $name indexed */
public $teams_names;
/* parses CSV file
* creates new Staff_Employee objects
* creates new Staff_Team objects
* adds references to each Staff_Employee::$managers and Staff_Employee::$team
* adds references to Staff_Team::$managers and Staff_Team::$staff */
public __construct();
/* returns a single Staff_Employee object */
public get_employee($name) {};
/* returns a single Staff_Team object */
public get_team($name) {};
}
class Staff_Employee {
/* string */
public $name;
/* array containing all Employee's managers as Staff_Employee objects */
public $managers;
/* Staff_Team object of the team the Employee is in */
public $team;
}
class Staff_Team {
/* string */
public $name;
/* array of all managers in the team (Staff_Employee objects) */
public $managers;
/* array of all non-managers in the team (Staff_Employee objects) */
public $staff;
}
Now, at the moment there are no references used in the application. All object variables are passed-by-value. I thought this could potentially have some overhead. So once all Employee and Team objects are created I have simply tried changing all calls to those to references, e.g.:
$team1->managers[] = &$employee1;
$employee0->managers[] = &$employee1;
But this momentarily increased memory usage which was surprising to me. The example I'm using has only 200 worth of staff, but I can imagine that when having to deal with enterprises this can go up to thousands or even more and the memory usage would grow even more.
When I was thinking of this example, I tried to mimic ORM where I could do something like this:
$team->staff[n]->managers[n]->name; // infinite chaining?
Ideally the "proper" (initial?) objects would only be stored in Staff::$employees
and Staff::$teams
, so then Staff::$teams_names['Team Name']
would be a reference to Staff::$teams[n]
. Similarly Staff_Team::$managers
would be an array of references to Staff::$employees
, etc.
Question(s):
So how should I handle this then? Should I use pass-by-reference and don't worry about memory usage, or should I use pass-by-value? Which one's better in this case and why?Note1: I (think I) do understand the difference between passing an object by value and by reference. I'm only asking which one's better in this example.
Note2: There might be some manipulation to Staff_Employee object after it's created. Probably very minimal though.Short answer: Don't use ampersands, "pass-by-value" (which confusingly enough, is referred as pass-by-reference in other languages.)
Longer answer: I think some example code will be the most explanatory:
$a = new stdclass();
$b = $a;
$c = &$a;
$a->field = 'asdf';
echo '$b->field = ' . $b->field . "\n"; // $b->field = asdf
echo '$c->field = ' . $c->field . "\n"; // $c->field = asdf
So if you simply assign to fields of an object, there is no difference. The ampersand only makes a difference if you overwrite the variable itself.
$a = new stdclass();
$b = $a;
$c = &$a;
$a = 2;
echo 'is_object($b) = ' . is_object($b) . "\n"; // is_object($b) = 1
echo 'is_object($c) = ' . is_object($c) . "\n"; // is_object($c) = 0
But generally, that sort of behavior is bad juju (and only useful if you're trying to, say, return multiple values from a function; which you could also use list()
for.)
精彩评论