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());
}
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
<?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
$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;
}
}
}
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, bec. you need to retrieve generator anyway, so better to revise approach for discovering the $project
.
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 $project
in the constructor
$auth = new Auth($other_default_value);
$auth->check('user2')->project(); // returns $other_default_value
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 "
";
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.