1

If I want to access the public method, I can do that easily. But if I want to access the property within method, what should I do, and is it recommended??

Can I do something like this in php?

class Auth {
   public function check($user = false){
    $project = false; //make it somehow public
     if($user == 'user1'){
       $this->project = 1;
     }
   }
}

and than in some other place

$auth = new Auth();
$auth->check('user1')->project;

Just so you people know its possible here is the Zend framework code from

Zend-Authentication

 if ($result->isValid()) {
            $this->getStorage()->write($result->getIdentity());
        }
1
  • 3
    typo $this-project = 1; should be $this->project = 1; Commented Feb 13, 2017 at 18:26

6 Answers 6

3
+50

I believe your question is basically regarding Fluent Interfaces or Method Chaining in conjunction with the magic method __get

Attempting to run this:

<?php
class Auth {
   public function check($user = false){
    $project = false; //make it somehow public
     if($user == 'user1'){
       $this->project = 1;
     }
   }
}

$auth = new Auth();
$auth->check('user1')->project;

Results in:

Notice: Trying to get property of non-object in /in/Hi5Rc on line 13

because $auth->check('user1') returns NULL (or void) and NULL doesn't have a project property.

The first thing we require is for $auth->check('user1') to return something useful. Given that $project is a boolean and $this->project is an integer, it makes the most sense to just return $project and get the value.

<?php
class Auth {
   public function check($user = false){
    $project = false; //make it somehow public
     if($user == 'user1'){
       $this->project = 1;
     }
    return $project;
   }
}

$auth = new Auth();
print_r($auth->check('user1'));

which results in :

bool(false)

But that doesn't address your question about how to fluently access a nonpublic field or parameter.

It appears that you are operating under the misconception that these projects are taking method scoped variables like $project in your check() class and making them accessible. They are not.

Not even in your example of the Zend-Authentication.

The field $storage itself is protected, but it has public (fluent) getters/setters.

So, $this->getStorage() returns an instance of new Storage\Session() which has a public write().

Thus $this->getStorage()->write() works.

So lets take your example class and modify it a bit to demonstrate.

<?php
class Project{
    /**
     * @var string
     */
    private $name;
    /**
     * @var bool
     */
    private $active;
    /**
     * @var string
     */
    private $description;

    public function __construct($name = 'Default', $active = false, $description = '')
    {
        $this->name = $name;
        $this->active = $active;
        $this->description = $description;
    }

    /**
     * @param string $name
     *
     * @return Project
     */
    public function setName(string $name): Project
    {
        $this->name = $name;

        return $this;
    }

    /**
     * @param bool $active
     *
     * @return Project
     */
    public function setActive(bool $active): Project
    {
        $this->active = $active;

        return $this;
    }

    /**
     * @param string $description
     *
     * @return Project
     */
    public function setDescription(string $description): Project
    {
        $this->description = $description;

        return $this;
    }

    /**
     * @return string
     */
    public function getName(): string
    {
        return $this->name;
    }

    /**
     * @return bool
     */
    public function isActive(): bool
    {
        return $this->active;
    }

    /**
     * @return string
     */
    public function getDescription(): string
    {
        return $this->description;
    }

    public function toArray(){
        return [
            'name' => $this->name,
            'active' => $this->active,
            'description' => $this->description
        ];
    }

    public function toJson(){
        return json_encode($this->toArray());
    }

    public function __toString()
    {
        return $this->toJson();
    }
}



class Auth {

    /**
     * @var Project
     */
    private $project;

    public function __construct($project = Null)
    {
        $this->project = is_null($project)? new Project() : $project;
    }

    public function check($user = false){
        if($user == 'user1'){
            $this->project->setName("Project: $user")->setActive(true)->setDescription("This project belongs to $user");
        }
        return $this;
    }

    /**
     * @param Project $project
     *
     * @return Auth
     */
    public function setProject(Project $project): Auth
    {
        $this->project = $project;

        return $this;
    }

    /**
     * @return Project
     */
    public function getProject(): Project
    {
        return $this->project;
    }

}

$auth = new Auth();
echo $auth->check('user1')->getProject();

now results in:

{"name":"Project: user1","active":true,"description":"This project belongs to user1"}

However, you wanted to access the private field as if it were a public field without using a defined getter/setter. So lets make some more changes to the Auth class.

class Auth {

    /**
     * @var Project[]
     */
    private $private_project;

    public function __construct($project = Null)
    {
        $this->private_project = is_null($project)? new Project() : $project;
    }

    public function check($user = false){
        if($user == 'user1'){
            $this->private_project->setName("Project: $user")->setActive(true)->setDescription("This project belongs to $user");
        }
        return $this;
    }

    public function __get($name)
    {
        if ($name === 'project'){
            return $this->private_project;
        }
    }

}

Now you can fluently access the field as you requested:

$auth = new Auth();
echo $auth->check('baduser')->project;
echo  "\n";
echo $auth->check('user1')->project;

results in:

{"name":"Default","active":false,"description":""}

{"name":"Project: user1","active":true,"description":"This project belongs to user1"}

Laravel's Eloquent models make great use of the __get()function for accessing model fields dynamically. Laravel also makes great use of the __call() magic method for fluency.

I hope that helps bring some clarity.

Sign up to request clarification or add additional context in comments.

Comments

3
class Auth
{
   protected $project;

   public function __constructor($project = false)
   {
        $this->project = $project;
   }

   public function check($user = false)
   {
     if($user == 'user1')
     {
       $this->project = 1;
     }

      return $this;
   }

   public function project()
   {
       return $this->project;
   }
}

then you can do the following:

$auth = new Auth();
$auth->check('user1')->project(); // returns 1

or if you want you can also set another default value for the $projectin the constructor

$auth = new Auth($other_default_value);
$auth->check('user2')->project();  // returns $other_default_value

Comments

1

If you don't want to create extra class properties and "preserve method chaining", what about yield?

class Auth
{
   public function check($user = false)
   {
       $project = false; // make it somehow public

       if($user === 'user1'){
           (yield 'project' => $project); // making it public
       }

       return $this;
   }
}

Later on you can discover it as follows:

$array = iterator_to_array($auth->check($user));
// array(1) { ["project"] => bool(false) }

But for this to use you won't be able to use method chaining, because you need to retrieve generator anyway, so better to revise approach for discovering the $project.

Comments

0
<?php
class Auth
{
    public $project;
    public function check($user = false)
    {
        $this->project = false;//make it somehow public
        if ($user == 'user1') {
            $this->project = 1;
        }
        return $this;
    }
}

$auth = new Auth();
var_dump($auth->check('user1')->project);

This will return you 1. The local variables defined in function are only accessbile inside the function not outside hence you need to define them globally

4 Comments

$auth->project; works but $auth->check()->project; doesn't gives the error
because $project is the property of class not function
a function doesn't have property.. property is for class .. so the class return instance of itself and thats why through the function you are able to access the property of the class. A function /method doesn't hold any property
haha, that was my question that it is not working. yours is not working either
0

$project is a local variable in your case, visible within the scope of the check method. You could define it as a member:

class Auth {
   public $project = false;
   public function check($user = false){
     if($user == 'user1'){
       $this-project = 1;
     }
   }
}

However, it is recommendable to make the member public and reach it via a getter, which will check whether it was initialized and if not, initialize it:

class Auth {
   private $project = false;
   public getProject($user = false) {
      if ($this->project === false) {
          check($user);
      }
      return $this->project;
   }
   public function check($user = false){
     if($user == 'user1'){
       $this-project = 1;
     }
   }
}

Comments

0

You will need to add it as a class variable:

class Auth {
   public $project = false;

   public function check($user = false) {
     if($user == 'user1'){
       $this->project = 1;
     }
   }
}

The property is then available as follows:

$auth = new Auth ();
$auth->check ('user1');
echo $auth->project; // 1

3 Comments

Trying to get property of non-object
$auth->project; works but $auth->check()->project; doesn't gives the error
OK, point made. I thought the syntax was given as a way to try and access a variable within a function. Since the user doesn't understand about class variables, my assumption was that they wouldn't understand the class returning an instance of itself.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.