Reputation: 1640
Let's say I have this:
class "classname"
{
....
public function section($id)
{
// variable method name
$this->section->$id = new stdClass();
return $this;
}
public function subsection()
{
// $id is not available here
$this->section->$id->subsection = array();
return $this;
}
....
}
When I call:
$classname->section("test")
->subsection();
It is not working because $id is not global nor set in the second chainlink. Do I have to pass it manually to ->subsection($id) or is there a more generic/cleaner way to get it there?
What I try to accomplish here is to create an (big) object with multiple sections. In these sections objects and/or array's so there are more (chained) methods involved.
Upvotes: 0
Views: 2247
Reputation: 3636
Consider using 2 classes to accomplish what you want. Here is an example
class Document
{
private $sections = array();
public function addSection(Section $section)
{
$this->sections[] = $section;
}
public function getSections()
{
print_r($this->sections);
}
}
class Section {
private $id;
private $subsection;
public function setId($id)
{
$this->id = $id;
return $this;
}
public function setSubsection()
{
$this->subsection = array();
return $this;
}
}
$section1 = new Section;
$section1->setId(1)->setSubsection();
$section2 = new Section;
$section2->setId(2)->setSubsection();
$document = new Document;
$document->addSection($section1);
$document->addSection($section2);
$document->getSections();
will output
Array (
[0] => Section Object ([id:protected] => 1 [subsection:protected] => Array( ))
[1] => Section Object ([id:protected] => 2 [subsection:protected] => Array( )))
Upvotes: 0
Reputation: 6968
The problem you're facing is not because of chaining methods. It occurs either because you haven't declared the property $section
or if you've declared it it has no property $id
.
One possibility would be to define $section
on the fly in the same way you're doing it with $id
, i.e.
public function section($id) {
$this->section = new stdClass();
$this->section->id = new stdClass();
return $this;
}
or
class Classname {
private $section;
public function __construct() {
$this->section = new stdClass();
}
public function section($id) {
$this->section->id = new stdClass();
return $this;
}
}
or
class Classname {
private $section;
public function __construct() {
$this->section = new B();
}
public function section($id) {
$this->section->id = new stdClass();
return $this;
}
}
class B {
private $id;
}
Upvotes: 0
Reputation: 37365
You can act like this way:
class Foo
{
protected $section;
private $lastUsedId = null;
public function __construct()
{
$this->section = new StdClass();
}
public function section($id)
{
// variable method name
$this->section->$id = new StdClass();
$this->lastUsedId = $id;
return $this;
}
public function subsection()
{
// $id is not available here
$this->section->{$this->lastUsedId}->subsection = array();
return $this;
}
}
so
$obj = (new Foo())
->section('one')
->subsection()
->section('two')
->subsection();
will produce valid result like
object(Foo)#1 (2) { ["section":protected]=> object(stdClass)#2 (2) { ["one"]=> object(stdClass)#3 (1) { ["subsection"]=> array(0) { } } ["two"]=> object(stdClass)#4 (1) { ["subsection"]=> array(0) { } } } ["lastUsedId":"Foo":private]=> string(3) "two" }
Note, that it isn't a good idea to use chaining like this way - it's difficult to read, and, besides, having method that actually changes data, but looks like getter, is confusing.
Upvotes: 5