Search code examples
phpmethod-chaining

Chain methods ability without force to new keyword using php


I'm working on a script that MUST to call like this:

$father = Father::firstName('Esaaro')->lastName('Ozaaraa')->age(42);

Person::firstName("Soobaasaa")->lastName( "Ozaaraa")->age(17)
  ->setFather( $father )-> toArray();

So we have two classes named Person and Father.

firstName method of two classes are static methods and other methods are public.

This is my file structure

<?php

class Person
{
    protected static $name;
    protected $lastName, $age, $father, $result;

    public static function firstName($name = null)
    {
        self::$name = $name;
    }

    public function lastName($lastName = null)
    {
        $this->lastName = $lastName;
    }

    public function age($age = null)
    {
        $this->age = $age;
    }

    public function toArray()
    {

    }

    public function setFather(Father $father)
    {

    }
}


    /*
     * Father Class
     */

class Father
{
    protected static $name;
    protected $family, $age, $result;

    public static function firstName($name = null)
    {
        self::$name = $name;
    }

    public function lastName($lastName = null)
    {
        $this->family = $lastName;
    }

    public function age($age = null)
    {
        $this->age = $age;
    }

    public function toArray()
    {
        ( (isset(static::$name) && static::$name !== null) ? $this->result['firsName'] = self::$name : '' );
        ( (isset($this->family) && $this->family !== null) ? $this->result['lastName'] = $this->family : '' );

        return $this->result;
    }
}

the above code is just structure and I just started to work on script. The file structure could not change because it's a challenge.

How should I manipulate my script that I can call methods like I mentioned before?

Thanks in Advance


Solution

  • Really all you need is for the static firstName methods to create a new instance of the class and return it.

    The other setters just need to return $this to provide what's referred to as a fluent interface.

    If the only way to create an instance is via the static firstName method, you'll also want to add a private / protected constructor.

    For example

    class Person
    {
        private $firstName;
        private $lastName;
        private $age;
        private $father;
    
        private function __construct(string $firstName) {
            $this->firstName = $firstName;
        }
    
        public static function firstName(string $name) {
            return new Person($name);
        }
    
        public function lastName(string $lastName) {
            $this->lastName = $lastName;
            return $this;
        }
    
        public function age(int $age) {
            $this->age = $age;
            return $this;
        }
    
        public function setFather(Father $father) {
            $this->father = $father;
            return $this;
        }
    
        public function toArray() {
            // just an example
            return [
                'firstName' => $this->firstName,
                'lastName'  => $this->lastName,
                'age'       => $this->age,
                'father'    => $this->father->toArray(),
            ];
        }
    }
    

    I would strongly advise against keeping the $name property as static. You don't want to change one instance's $name and have it change all others. This is why I've changed it to private $firstName in my example above.