Question

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.

Was it helpful?

Solution

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.

OTHER TIPS

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;

}

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( )))
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top