Одним из решений этой проблемы было бы переопределение __get в классе Zoo для возврата класса 'creator'.
function __get($animal){
return new Creator($this, $animal);
}
Тогда пусть класс создателя вызовет функцию add в классе zoo.
class Creator{
public function __construct($zoo, $animal){
....
}
public function add($details){
$zoo->add($this->_animal, $details);
}
}
Это решение довольно уродливо, и с точки зрения будущих разработчиков, не так ясно. Как отмечено в комментариях, есть лучшие способы обойти это. Делать что-то вроде:
$zoo->add('lion', 'whatever')
или
$zoo->add( new Lion('Whatever') )
Может быть, лучшее решение, и, по моему мнению, другим разработчикам уже ясно, что происходит. (Это может быть не так, потому что я не знаю деталей того, что именно вы делаете).