PHP | Access to undeclared static property - php

After trying several attempts at this for some reason i get the error Access to undeclared static property when i try to make an object out my class.
My class:
final class repo {
var $b;
/**
* #var \Guzzle\Http\Client
*/
protected $client;
function repo($myvar)
{
static::$b = $myvar;
$this->client = $b;
}
}
Me making an object:
$myobj = new repo("test");

You should declare $b as static variable.
Also note that method as a class name is deprecated now see the details here
final class repo {
public static $b;
/**
* #var \Guzzle\Http\Client
*/
protected $client;
function repo($myvar)
{
static::$b = $myvar;
$this->client = static::$b;
}
}

The declaration var $b; is PHP 4. PHP 5 allows it and it is equivalent to public $b;.
However, it is deprecated and if you use a proper error reporting (error_reporting(E_ALL); during development) you get a warning about it. You should use the PHP 5 visibility kewords instead.
Also, the declaration function repo($myvar) is a PHP 4 constructor style, also accepted but deprecated. You should use the PHP 5 __constructor() syntax.
You access $b as static::$b and this is not compatible with its declaration (equivalent, as I said above, with public $b). If you want it to be a class property (this is what static does) you have to declare it as a class property (i.e. public static $b).
Putting everything together, the proper way to write your class is:
final class repo {
// public static members are global variables; avoid making them public
/** #var \Guzzle\Http\Client */
private static $b;
// since the class is final, "protected" is the same as "private"
/** #var \Guzzle\Http\Client */
protected $client;
// PHP 5 constructor. public to allow the class to be instantiated.
// $myvar is probably a \Guzzle\Http\Client object
public __construct(\Guzzle\Http\Client $myvar)
{
static::$b = $myvar;
// $this->b probably works but static::$b is more clear
// because $b is a class property not an instance property
$this->client = static::$b;
}
}

Try this
final class repo {
public $b;
/**
* #var \Guzzle\Http\Client
*/
protected $client;
function repo($myvar)
{
$this->b = $myvar;
$this->client = $this->b;
}
}
Note: static::/self:: is used on static functions.

Related

How to assign types in php without causing parse errors? [duplicate]

Does php 7 support type hinting for class properties?
I mean, not just for setters/getters but for the property itself.
Something like:
class Foo {
/**
*
* #var Bar
*/
public $bar : Bar;
}
$fooInstance = new Foo();
$fooInstance->bar = new NotBar(); //Error
PHP 7.4 will support typed properties like so:
class Person
{
public string $name;
public DateTimeImmutable $dateOfBirth;
}
PHP 7.3 and earlier do not support this, but there are some alternatives.
You can make a private property which is accessible only through getters and setters which have type declarations:
class Person
{
private $name;
public function getName(): string {
return $this->name;
}
public function setName(string $newName) {
$this->name = $newName;
}
}
You can also make a public property and use a docblock to provide type information to people reading the code and using an IDE, but this provides no runtime type-checking:
class Person
{
/**
* #var string
*/
public $name;
}
And indeed, you can combine getters and setters and a docblock.
If you're more adventurous, you could make a fake property with the __get, __set, __isset and __unset magic methods, and check the types yourself. I'm not sure if I'd recommend it, though.
7.4+:
Good news that it will be implemented in the new releases, as #Andrea pointed out.
I will just leave this solution here in case someone wants to use it prior to 7.4
7.3 or less
Based on the notifications I still receive from this thread, I believe that many people out there had/is having the same issue that I had. My solution for this case was combining setters + __set magic method inside a trait in order to simulate this behaviour.
Here it is:
trait SettersTrait
{
/**
* #param $name
* #param $value
*/
public function __set($name, $value)
{
$setter = 'set'.$name;
if (method_exists($this, $setter)) {
$this->$setter($value);
} else {
$this->$name = $value;
}
}
}
And here is the demonstration:
class Bar {}
class NotBar {}
class Foo
{
use SettersTrait; //It could be implemented within this class but I used it as a trait for more flexibility
/**
*
* #var Bar
*/
private $bar;
/**
* #param Bar $bar
*/
protected function setBar(Bar $bar)
{
//(optional) Protected so it wont be called directly by external 'entities'
$this->bar = $bar;
}
}
$foo = new Foo();
$foo->bar = new NotBar(); //Error
//$foo->bar = new Bar(); //Success
Explanation
First of all, define bar as a private property so PHP will cast __set automagically.
__set will check if there is some setter declared in the current object (method_exists($this, $setter)). Otherwise it will only set its value as it normally would.
Declare a setter method (setBar) that receives a type-hinted argument (setBar(Bar $bar)).
As long as PHP detects that something that is not Bar instance is being passed to the setter, it will automaticaly trigger a Fatal Error: Uncaught TypeError: Argument 1 passed to Foo::setBar() must be an instance of Bar, instance of NotBar given
Edit for PHP 7.4 :
Since PHP 7.4 you can type attributes (Documentation / Wiki) which means you can do :
class Foo
{
protected ?Bar $bar;
public int $id;
...
}
According to wiki, all acceptable values are :
bool, int, float, string, array, object
iterable
self, parent
any class or interface name
?type // where "type" may be any of the above
PHP < 7.4
It is actually not possible and you only have 4 ways to actually simulate it :
Default values
Decorators in comment blocks
Default values in constructor
Getters and setters
I combined all of them here
class Foo
{
/**
* #var Bar
*/
protected $bar = null;
/**
* Foo constructor
* #param Bar $bar
**/
public function __construct(Bar $bar = null){
$this->bar = $bar;
}
/**
* #return Bar
*/
public function getBar() : ?Bar{
return $this->bar;
}
/**
* #param Bar $bar
*/
public function setBar(Bar $bar) {
$this->bar = $bar;
}
}
Note that you actually can type the return as ?Bar since php 7.1 (nullable) because it could be null (not available in php7.0.)
You also can type the return as void since php7.1
You can use setter
class Bar {
public $val;
}
class Foo {
/**
*
* #var Bar
*/
private $bar;
/**
* #return Bar
*/
public function getBar()
{
return $this->bar;
}
/**
* #param Bar $bar
*/
public function setBar(Bar $bar)
{
$this->bar = $bar;
}
}
$fooInstance = new Foo();
// $fooInstance->bar = new NotBar(); //Error
$fooInstance->setBar($fooInstance);
Output:
TypeError: Argument 1 passed to Foo::setBar() must be an instance of Bar, instance of Foo given, called in ...

PHP PSR-12 is this a syntax error in example? [duplicate]

Does php 7 support type hinting for class properties?
I mean, not just for setters/getters but for the property itself.
Something like:
class Foo {
/**
*
* #var Bar
*/
public $bar : Bar;
}
$fooInstance = new Foo();
$fooInstance->bar = new NotBar(); //Error
PHP 7.4 will support typed properties like so:
class Person
{
public string $name;
public DateTimeImmutable $dateOfBirth;
}
PHP 7.3 and earlier do not support this, but there are some alternatives.
You can make a private property which is accessible only through getters and setters which have type declarations:
class Person
{
private $name;
public function getName(): string {
return $this->name;
}
public function setName(string $newName) {
$this->name = $newName;
}
}
You can also make a public property and use a docblock to provide type information to people reading the code and using an IDE, but this provides no runtime type-checking:
class Person
{
/**
* #var string
*/
public $name;
}
And indeed, you can combine getters and setters and a docblock.
If you're more adventurous, you could make a fake property with the __get, __set, __isset and __unset magic methods, and check the types yourself. I'm not sure if I'd recommend it, though.
7.4+:
Good news that it will be implemented in the new releases, as #Andrea pointed out.
I will just leave this solution here in case someone wants to use it prior to 7.4
7.3 or less
Based on the notifications I still receive from this thread, I believe that many people out there had/is having the same issue that I had. My solution for this case was combining setters + __set magic method inside a trait in order to simulate this behaviour.
Here it is:
trait SettersTrait
{
/**
* #param $name
* #param $value
*/
public function __set($name, $value)
{
$setter = 'set'.$name;
if (method_exists($this, $setter)) {
$this->$setter($value);
} else {
$this->$name = $value;
}
}
}
And here is the demonstration:
class Bar {}
class NotBar {}
class Foo
{
use SettersTrait; //It could be implemented within this class but I used it as a trait for more flexibility
/**
*
* #var Bar
*/
private $bar;
/**
* #param Bar $bar
*/
protected function setBar(Bar $bar)
{
//(optional) Protected so it wont be called directly by external 'entities'
$this->bar = $bar;
}
}
$foo = new Foo();
$foo->bar = new NotBar(); //Error
//$foo->bar = new Bar(); //Success
Explanation
First of all, define bar as a private property so PHP will cast __set automagically.
__set will check if there is some setter declared in the current object (method_exists($this, $setter)). Otherwise it will only set its value as it normally would.
Declare a setter method (setBar) that receives a type-hinted argument (setBar(Bar $bar)).
As long as PHP detects that something that is not Bar instance is being passed to the setter, it will automaticaly trigger a Fatal Error: Uncaught TypeError: Argument 1 passed to Foo::setBar() must be an instance of Bar, instance of NotBar given
Edit for PHP 7.4 :
Since PHP 7.4 you can type attributes (Documentation / Wiki) which means you can do :
class Foo
{
protected ?Bar $bar;
public int $id;
...
}
According to wiki, all acceptable values are :
bool, int, float, string, array, object
iterable
self, parent
any class or interface name
?type // where "type" may be any of the above
PHP < 7.4
It is actually not possible and you only have 4 ways to actually simulate it :
Default values
Decorators in comment blocks
Default values in constructor
Getters and setters
I combined all of them here
class Foo
{
/**
* #var Bar
*/
protected $bar = null;
/**
* Foo constructor
* #param Bar $bar
**/
public function __construct(Bar $bar = null){
$this->bar = $bar;
}
/**
* #return Bar
*/
public function getBar() : ?Bar{
return $this->bar;
}
/**
* #param Bar $bar
*/
public function setBar(Bar $bar) {
$this->bar = $bar;
}
}
Note that you actually can type the return as ?Bar since php 7.1 (nullable) because it could be null (not available in php7.0.)
You also can type the return as void since php7.1
You can use setter
class Bar {
public $val;
}
class Foo {
/**
*
* #var Bar
*/
private $bar;
/**
* #return Bar
*/
public function getBar()
{
return $this->bar;
}
/**
* #param Bar $bar
*/
public function setBar(Bar $bar)
{
$this->bar = $bar;
}
}
$fooInstance = new Foo();
// $fooInstance->bar = new NotBar(); //Error
$fooInstance->setBar($fooInstance);
Output:
TypeError: Argument 1 passed to Foo::setBar() must be an instance of Bar, instance of Foo given, called in ...

Type hinting for properties in PHP 7?

Does php 7 support type hinting for class properties?
I mean, not just for setters/getters but for the property itself.
Something like:
class Foo {
/**
*
* #var Bar
*/
public $bar : Bar;
}
$fooInstance = new Foo();
$fooInstance->bar = new NotBar(); //Error
PHP 7.4 will support typed properties like so:
class Person
{
public string $name;
public DateTimeImmutable $dateOfBirth;
}
PHP 7.3 and earlier do not support this, but there are some alternatives.
You can make a private property which is accessible only through getters and setters which have type declarations:
class Person
{
private $name;
public function getName(): string {
return $this->name;
}
public function setName(string $newName) {
$this->name = $newName;
}
}
You can also make a public property and use a docblock to provide type information to people reading the code and using an IDE, but this provides no runtime type-checking:
class Person
{
/**
* #var string
*/
public $name;
}
And indeed, you can combine getters and setters and a docblock.
If you're more adventurous, you could make a fake property with the __get, __set, __isset and __unset magic methods, and check the types yourself. I'm not sure if I'd recommend it, though.
7.4+:
Good news that it will be implemented in the new releases, as #Andrea pointed out.
I will just leave this solution here in case someone wants to use it prior to 7.4
7.3 or less
Based on the notifications I still receive from this thread, I believe that many people out there had/is having the same issue that I had. My solution for this case was combining setters + __set magic method inside a trait in order to simulate this behaviour.
Here it is:
trait SettersTrait
{
/**
* #param $name
* #param $value
*/
public function __set($name, $value)
{
$setter = 'set'.$name;
if (method_exists($this, $setter)) {
$this->$setter($value);
} else {
$this->$name = $value;
}
}
}
And here is the demonstration:
class Bar {}
class NotBar {}
class Foo
{
use SettersTrait; //It could be implemented within this class but I used it as a trait for more flexibility
/**
*
* #var Bar
*/
private $bar;
/**
* #param Bar $bar
*/
protected function setBar(Bar $bar)
{
//(optional) Protected so it wont be called directly by external 'entities'
$this->bar = $bar;
}
}
$foo = new Foo();
$foo->bar = new NotBar(); //Error
//$foo->bar = new Bar(); //Success
Explanation
First of all, define bar as a private property so PHP will cast __set automagically.
__set will check if there is some setter declared in the current object (method_exists($this, $setter)). Otherwise it will only set its value as it normally would.
Declare a setter method (setBar) that receives a type-hinted argument (setBar(Bar $bar)).
As long as PHP detects that something that is not Bar instance is being passed to the setter, it will automaticaly trigger a Fatal Error: Uncaught TypeError: Argument 1 passed to Foo::setBar() must be an instance of Bar, instance of NotBar given
Edit for PHP 7.4 :
Since PHP 7.4 you can type attributes (Documentation / Wiki) which means you can do :
class Foo
{
protected ?Bar $bar;
public int $id;
...
}
According to wiki, all acceptable values are :
bool, int, float, string, array, object
iterable
self, parent
any class or interface name
?type // where "type" may be any of the above
PHP < 7.4
It is actually not possible and you only have 4 ways to actually simulate it :
Default values
Decorators in comment blocks
Default values in constructor
Getters and setters
I combined all of them here
class Foo
{
/**
* #var Bar
*/
protected $bar = null;
/**
* Foo constructor
* #param Bar $bar
**/
public function __construct(Bar $bar = null){
$this->bar = $bar;
}
/**
* #return Bar
*/
public function getBar() : ?Bar{
return $this->bar;
}
/**
* #param Bar $bar
*/
public function setBar(Bar $bar) {
$this->bar = $bar;
}
}
Note that you actually can type the return as ?Bar since php 7.1 (nullable) because it could be null (not available in php7.0.)
You also can type the return as void since php7.1
You can use setter
class Bar {
public $val;
}
class Foo {
/**
*
* #var Bar
*/
private $bar;
/**
* #return Bar
*/
public function getBar()
{
return $this->bar;
}
/**
* #param Bar $bar
*/
public function setBar(Bar $bar)
{
$this->bar = $bar;
}
}
$fooInstance = new Foo();
// $fooInstance->bar = new NotBar(); //Error
$fooInstance->setBar($fooInstance);
Output:
TypeError: Argument 1 passed to Foo::setBar() must be an instance of Bar, instance of Foo given, called in ...

phpdoc #var in php file

i have next php code
<?php
class A {
public function foo() {
}
}
/**
* #var A $a
*/
$a->
I want to make my ide autocomplete $a-> correct, and show me that there is only one available method foo in $a. There is no any string like $a = new A();
$a instantiated in another place and handled by autoloader.
The following syntax works fine in eclipse
/* #var $a A */
$a->
Note that I switched parameters order.
For some reason PDT in Eclipse swaps the order of the #var parameters. This syntax works:
<?php
class A {
public function foo() {
}
}
/**
* #var $a A
*/
$a->
I'm using a variant of eloquent that autopopulates variables and the autohinting utterly fails in my eclipse, wether I place it above, under it, single line, multi line comments.
I did find a way in which it does work for me.
class Foo extends Model {
public function beforeSave() {
$bar = $this->bar;
foreach($bar as $baz) {
$baz-> // <-- this works now \o/
}
}
/**
* #return \Foo\Baz\Models\Bar
*/
public function getBar() {
return $this->bar;
}
}

Declaring a new static variable outside of Class

Is there a way declaring new static variables outside of that class even if it's not set in class?
// Using this class as a static object.
Class someclass {
// There is no definition for static variables.
}
// This can be initialized
Class classA {
public function __construct() {
// Some codes goes here
}
}
/* Declaration */
// Notice that there is no static declaration for $classA in someclass
$class = 'classA'
someclass::$$class = new $class();
How can it be done?
Thank you for your advices.
This can't be done, because static variables, well... are STATIC and therefore cannot be declared dynamically.
EDIT:
You might want to try using a registry.
class Registry {
/**
*
* Array of instances
* #var array
*/
private static $instances = array();
/**
*
* Returns an instance of a given class.
* #param string $class_name
*/
public static function getInstance($class_name) {
if(!isset(self::$instances[$class_name])) {
self::$instances[$class_name] = new $class_name;
}
return self::$instances[$class_name];
}
}
Registry::getInstance('YourClass');
__get() magic method in PHP is called when you access non-existent property of an object.
http://php.net/manual/en/language.oop5.magic.php
You may have a container within which you'll handle this.
Edit:
See this:
Magic __get getter for static properties in PHP

Categories