I have the following class in PHP:
class myClass extends AJAX_Callable {
public static $classGlobal = 'myVariable' ;
private static $types_fields = array(
'myArray' => array(
'name' => $classGlobal,
'age' => 'twenty five')
);
}
But this is not working
From the documentation:
Class member variables are called "properties". You may also see them referred to using other terms such as "attributes" or "fields", but for the purposes of this reference we will use "properties". They are defined by using one of the keywords public, protected, or private, followed by a normal variable declaration. This declaration may include an initialization, but this initialization must be a constant value--that is, it must be able to be evaluated at compile time and must not depend on run-time information in order to be evaluated.
the only way I can think of doing it would be to move things into a constructor. But its still a really weird thing to want to do. There wouldnt be any point in using static as you cant use it in the conventional way.
class myClass extends AJAX_Callable {
public static $classGlobal;
private static $types_fields;
public function __construct() {
// parent::__construct(); // if you have one
$this->classGlobal = 'myVariable';
$this->types_fields = array(
'myArray' => array(
'name' => $this->classGlobal,
'age' => 'twenty five')
);
}
public function getTypes() {
return $this->types_fields;
}
}
$foo = new myClass();
var_dump($foo->getTypes());
fiddle
Related
In the following code, I want to assign an $settings's key, help to a constant class variable value, $To_default. However, I am told Constant expression contains invalid operations. Is there any way I can get around this?
class EmailClass extends PluginBase {
private $To_default = 'scrollout#stackoverflow.com';
protected $settings = array(
'To'=>array(
'type'=>'text',
'label'=>'To',
'help'=>$this->To_default, // Constant expression contains invalid operations
),
);
I've tried declaring $To_default in various ways including private const $To_default, static private $To_default, etc. but none worked. $settings is not static, as you can see, so I don't understand why this is a problem.
Don't know deep technical explanation for this but I think this is because normally you initialize properties in the constructor, like so:
class EmailClass
{
private $To_default = 'scrollout#stackoverflow.com'; // not a constant, so better throw it into constructor too
protected $settings;
public function __construct() {
$this->settings = array(
'To'=>array(
'type'=>'text',
'label'=>'To',
'help'=>$this->To_default
)
);
}
}
Analogical I don't know why: 'if isset(expression)' doesn't work but it doesn't have to. There's a better solution: 'if(expression)'. This is just how we do it.
You can not specify a default value that refers to another class property ($settings is an array that tries to read $To_default).
My recommendation is that $settings can be the result of a getter method, for example getSettings, and inside of it you can build an array and return it.
By doing do this, you can also decide to override the $To_default value with a setTo method.
Here is an example:
<?php
class EmailClass extends PluginBase {
private string $toDefault = '';
/**
* #param string $toDefault
*/
public function __construct( string $toDefault = 'scrollout#stackoverflow.com' ) {
$this->toDefault = $toDefault;
}
/**
* #param string $toDefault
*/
public function setToDefault( string $toDefault ): void
{
$this->toDefault = $toDefault;
}
public function getSettings(): array
{
return [
'TO' => [
'type' => 'text',
'label' => 'To',
'help' => $this->toDefault,
]
];
}
}
Use a class constant rather than a variable for the default.
Constants don't begin with $, that's the problem you had when you tried this.
class EmailClass extends PluginBase {
private const TO_DEFAULT = 'scrollout#stackoverflow.com';
protected $settings = array(
'To'=>array(
'type'=>'text',
'label'=>'To',
'help'=>self::TO_DEFAULT, // Constant expression contains invalid operations
),
);
}
I tried to create a class with the properties like so:
class foo{
private $dbFields['test']=array("mobilePhone","address");
private $dbFields['test2']=array("mobilePhone","address",'colour');
}
but its not valid.
PHP Parse error: syntax error, unexpected '[', expecting ',' or ';' in
I had to do this which has the same result; but is less friendly for me editing in the future
class foo{
private $dbFields=array('test'=>array("mobilePhone","address"),'test2'=>array("mobilePhone","address",'colour'));
}
is there anyway to achieve the original structure or something simular?
You can do it with the following class properties syntax:
<?php
class foo {
private $dbFields = array(
'test' => array("mobilePhone","address"),
'test2' => array("mobilePhone","address","colour")
);
}
If the values are dynamic, and not as it looks (like a reference to database columns), then you should pass the values to the class constructor as suggested by B.Desai answer.
And if the values never change perhaps using a class constant would be nicer (PHP >=5.3.0).
<?php
class foo {
const dbFields = array(
'test' => array("mobilePhone","address"),
'test2' => array("mobilePhone","address","colour")
);
}
Always initialize class member in constructor. This way you can assign any dynamic value also to data member.
class foo{
private $dbFields;
function __construct()
{
$this->dbFields['test']=array("mobilePhone","address");
$this->dbFields['test2']=array("mobilePhone","address",'colour');
}
function getFields()
{
return $this->dbFields;
}
}
$obj = new foo();
print_r($obj->getFields());
I have a object having some protected property that I want to get and set. The object looks like
Fields_Form_Element_Location Object
(
[helper] => formText
[_allowEmpty:protected] => 1
[_autoInsertNotEmptyValidator:protected] => 1
[_belongsTo:protected] =>
[_description:protected] =>
[_disableLoadDefaultDecorators:protected] =>
[_errorMessages:protected] => Array
(
)
[_errors:protected] => Array
(
)
[_isErrorForced:protected] =>
[_label:protected] => Current City
[_value:protected] => 93399
[class] => field_container field_19 option_1 parent_1
)
I want to get value property of the object. When I try $obj->_value or $obj->value it generates error. I searched and found the solution to use PHP Reflection Class. It worked on my local but on server PHP version is 5.2.17 So I cannot use this function there. So any solution how to get such property?
Here's the really simple example (with no error checking) of how to use ReflectionClass:
function accessProtected($obj, $prop) {
$reflection = new ReflectionClass($obj);
$property = $reflection->getProperty($prop);
$property->setAccessible(true);
return $property->getValue($obj);
}
I know you said you were limited to 5.2, but that was 2 years ago, 5.5 is the oldest supported version and I'm hoping to help people with modern versions.
Object can be typecasted into (associative) array and the protected members have keys prefixed with chr(0).'*'.chr(0) (see #fardelian's comment here). Using this undocummented feature you can write an "exposer":
function getProtectedValue($obj, $name) {
$array = (array)$obj;
$prefix = chr(0).'*'.chr(0);
return $array[$prefix.$name];
}
Alternatively, you can parse the value from serialized string, where (it seems) protected members have the same prefix.
This works in PHP 5.2 without the overhead of ReflectionClass. However, there are reasons why some property is protected and hidden from client code. The reading or writing can make the data inconsistent or the author provides some other way to expose it in effort to make the interface as lean as possible. When there are reasons to read the protected property directly, the then-correct approach was to implement __get() magic method, so always check if there is any and see what it does. This counter intuitive lookup was finally solved in PHP 8.1 with readonly properties.
Since PHP 8.0, there also attributes metadata accessible by ReflectionClass, make sure to check them also before performing attempts to break into protected members. Attributes superseded "Annotations"1, so check them, too.
1: annotations are a very nasty surprise to client coders: they parse comments to add crazy fancy black-box useless confusing functionality, should not be used anymore, but they still exist
That's what "protected" is meant for, as the Visibility chapter explains:
Members declared protected can be accessed only within the class itself and by inherited and parent classes.
If you need to access the property from outside, pick one:
Don't declare it as protected, make it public instead
Write a couple of functions to get and set the value (getters and setters)
If you don't want to modify the original class (because it's a third-party library you don't want to mess) create a custom class that extends the original one:
class MyFields_Form_Element_Location extends Fields_Form_Element_Location{
}
... and add your getter/setter there.
If you want to tinker with a class without adding getters and setters....
PHP 7 adds a call($obj) method (faster than old bindTo) on closures allowing you to call a function so the $this variable will act just as it would within a class -with full permissions.
//test class with restricted properties
class test{
protected $bar="protected bar";
private $foo="private foo";
public function printProperties(){
echo $this->bar."::".$this->foo;
}
}
$testInstance=new test();
//we can change or read the restricted properties by doing this...
$change=function(){
$this->bar="I changed bar";
$this->foo="I changed foo";
};
$change->call($testInstance);
$testInstance->printProperties();
//outputs I changed bar::I changed foo in php 7.0
For PHP 7.4+, we can use an Arrow Function and the Closure::call to access private and protected members using just one small line:
PHP 7.4+
Retrieving protected/private members:
class Test {
protected $data = 'Protected variable!';
}
// Will output "Protected variable!"
echo (fn() => $this->data)->call(new Test);
Altering protected/private members:
class Test {
protected $data = 'Testing';
}
$test = new Test;
(fn() => $this->data = "New Data!")->call($test);
// Will output "New Data!"
echo (fn() => $this->data)->call($test);
Of course, we can use a normal Closure function if we want to alter/use multiple members:
class Test {
protected $data = 'Data!';
}
$test = new Test;
(function() {
$this->new_data = "New {$this->data}";
})->call($test);
// Will output "New Data!"
echo (fn() => $this->new_data)->call($test);
If you cannot modify the original class and extending it is not an option either, you can use the ReflectionProperty interface.
The phptoolcase library has a handy method for this:
$value = PtcHandyMan::getProperty($your_object , 'propertyName');
Static property from a singleton class:
$value = PtcHandyMan::getProperty('myCLassName', 'propertyName');
You can find the tool here: http://phptoolcase.com/guides/ptc-hm-guide.html
$a=json_encode((array)$obj);
$b=(array)json_decode(str_replace('\u0000*\u0000','',$a));
echo($b['value']);
What I like to do is declare every property that would be writable from outside as public. The properties that you want to be visible for the outside world but not writable you should declare as protected and write __get() magic method so you can read them. Example:
/**
* Class Test
*
* #property int $protected
*
*/
class Test
{
private const READABLE = ['protected'];
protected $protected = 1;
public $public = 2;
public function __get($property)
{
//if you want to read every protected or private
return $this->$property ?? null;
//if you want only some protected and private values to be readable
if (in_array($property, self::READABLE)) {
return $this->$property;
}
}
}
$test = new Test();
echo $test->protected; //outputs 1
echo $test->public; //outputs 2
$test->protected = 3; //outputs error - protected property
The best would be to have property declaration like:
public readonly $protected = 1; //only readable from the outside
public $public = 2; //readable and writable from the outside
but no such syntax exists yet(or... at least I don't know about it). P.S. you should declare the protected/private properties that will be readable in the Class DockBlock as shown, so you can autocomplete them, otherwise you will be able to access them, but your IDE won't recognize them on autocomplete when you are writing code.
I have a object having some protected property that I want to get and set. The object looks like
Fields_Form_Element_Location Object
(
[helper] => formText
[_allowEmpty:protected] => 1
[_autoInsertNotEmptyValidator:protected] => 1
[_belongsTo:protected] =>
[_description:protected] =>
[_disableLoadDefaultDecorators:protected] =>
[_errorMessages:protected] => Array
(
)
[_errors:protected] => Array
(
)
[_isErrorForced:protected] =>
[_label:protected] => Current City
[_value:protected] => 93399
[class] => field_container field_19 option_1 parent_1
)
I want to get value property of the object. When I try $obj->_value or $obj->value it generates error. I searched and found the solution to use PHP Reflection Class. It worked on my local but on server PHP version is 5.2.17 So I cannot use this function there. So any solution how to get such property?
Here's the really simple example (with no error checking) of how to use ReflectionClass:
function accessProtected($obj, $prop) {
$reflection = new ReflectionClass($obj);
$property = $reflection->getProperty($prop);
$property->setAccessible(true);
return $property->getValue($obj);
}
I know you said you were limited to 5.2, but that was 2 years ago, 5.5 is the oldest supported version and I'm hoping to help people with modern versions.
Object can be typecasted into (associative) array and the protected members have keys prefixed with chr(0).'*'.chr(0) (see #fardelian's comment here). Using this undocummented feature you can write an "exposer":
function getProtectedValue($obj, $name) {
$array = (array)$obj;
$prefix = chr(0).'*'.chr(0);
return $array[$prefix.$name];
}
Alternatively, you can parse the value from serialized string, where (it seems) protected members have the same prefix.
This works in PHP 5.2 without the overhead of ReflectionClass. However, there are reasons why some property is protected and hidden from client code. The reading or writing can make the data inconsistent or the author provides some other way to expose it in effort to make the interface as lean as possible. When there are reasons to read the protected property directly, the then-correct approach was to implement __get() magic method, so always check if there is any and see what it does. This counter intuitive lookup was finally solved in PHP 8.1 with readonly properties.
Since PHP 8.0, there also attributes metadata accessible by ReflectionClass, make sure to check them also before performing attempts to break into protected members. Attributes superseded "Annotations"1, so check them, too.
1: annotations are a very nasty surprise to client coders: they parse comments to add crazy fancy black-box useless confusing functionality, should not be used anymore, but they still exist
That's what "protected" is meant for, as the Visibility chapter explains:
Members declared protected can be accessed only within the class itself and by inherited and parent classes.
If you need to access the property from outside, pick one:
Don't declare it as protected, make it public instead
Write a couple of functions to get and set the value (getters and setters)
If you don't want to modify the original class (because it's a third-party library you don't want to mess) create a custom class that extends the original one:
class MyFields_Form_Element_Location extends Fields_Form_Element_Location{
}
... and add your getter/setter there.
If you want to tinker with a class without adding getters and setters....
PHP 7 adds a call($obj) method (faster than old bindTo) on closures allowing you to call a function so the $this variable will act just as it would within a class -with full permissions.
//test class with restricted properties
class test{
protected $bar="protected bar";
private $foo="private foo";
public function printProperties(){
echo $this->bar."::".$this->foo;
}
}
$testInstance=new test();
//we can change or read the restricted properties by doing this...
$change=function(){
$this->bar="I changed bar";
$this->foo="I changed foo";
};
$change->call($testInstance);
$testInstance->printProperties();
//outputs I changed bar::I changed foo in php 7.0
For PHP 7.4+, we can use an Arrow Function and the Closure::call to access private and protected members using just one small line:
PHP 7.4+
Retrieving protected/private members:
class Test {
protected $data = 'Protected variable!';
}
// Will output "Protected variable!"
echo (fn() => $this->data)->call(new Test);
Altering protected/private members:
class Test {
protected $data = 'Testing';
}
$test = new Test;
(fn() => $this->data = "New Data!")->call($test);
// Will output "New Data!"
echo (fn() => $this->data)->call($test);
Of course, we can use a normal Closure function if we want to alter/use multiple members:
class Test {
protected $data = 'Data!';
}
$test = new Test;
(function() {
$this->new_data = "New {$this->data}";
})->call($test);
// Will output "New Data!"
echo (fn() => $this->new_data)->call($test);
If you cannot modify the original class and extending it is not an option either, you can use the ReflectionProperty interface.
The phptoolcase library has a handy method for this:
$value = PtcHandyMan::getProperty($your_object , 'propertyName');
Static property from a singleton class:
$value = PtcHandyMan::getProperty('myCLassName', 'propertyName');
You can find the tool here: http://phptoolcase.com/guides/ptc-hm-guide.html
$a=json_encode((array)$obj);
$b=(array)json_decode(str_replace('\u0000*\u0000','',$a));
echo($b['value']);
What I like to do is declare every property that would be writable from outside as public. The properties that you want to be visible for the outside world but not writable you should declare as protected and write __get() magic method so you can read them. Example:
/**
* Class Test
*
* #property int $protected
*
*/
class Test
{
private const READABLE = ['protected'];
protected $protected = 1;
public $public = 2;
public function __get($property)
{
//if you want to read every protected or private
return $this->$property ?? null;
//if you want only some protected and private values to be readable
if (in_array($property, self::READABLE)) {
return $this->$property;
}
}
}
$test = new Test();
echo $test->protected; //outputs 1
echo $test->public; //outputs 2
$test->protected = 3; //outputs error - protected property
The best would be to have property declaration like:
public readonly $protected = 1; //only readable from the outside
public $public = 2; //readable and writable from the outside
but no such syntax exists yet(or... at least I don't know about it). P.S. you should declare the protected/private properties that will be readable in the Class DockBlock as shown, so you can autocomplete them, otherwise you will be able to access them, but your IDE won't recognize them on autocomplete when you are writing code.
Hey, everyone. I couldn't find anything Googling this problem, and I've found really good answers to some questions on SO before, so I'm taking this excuse to join the community.
I'm creating a hierarchy of classes for a PHP project I'm working on, and I'd like to have some variables in the classes initialized within the constructor function without explicitly writing the initialization code. Specifically I want to have the interpreter assume that some of the variables are actually pointers to a certain class. If I could do something like C structs, that would be pretty close to what I want.
So far, the only thing I came up with is to explicitly state the variable type within its own name and have the class call an initializing function on each, like;
class A{
...
}
class B{
var $x_A;
function initVar($var){
list($varname, $vartype) = split('_',$var);
$this->$var = new $vartype();
}
}
And B's constructor calls initVar on all of its get_class_vars(get_class($this)), so anything that inherits from it will do initialization in the same way; obviously including a check on the variable name, a check that the class exists, and a better separation scheme than a single underscore. I just cannot help but think that there is a better way to do this that isn't hardcoding the initialization into the construction function.
If anyone knows of a better way to do this, your help would be much appreciated.
Your method there would probably work, however it could get very tiresome to actually use it. For example, imagine having to reference those variables all the time:
$myObject->account_ServiceAccountType
If you really wanted to go with something like this, perhaps a mapping variable might be useful:
class B {
public $x, $account;
private $map = array(
'x' => 'A',
'account' => 'ServiceAccountType'
);
public function __construct() {
foreach ($this->map as $var => $class) {
$this->$var = new $class;
}
}
}
You could also try this method out. It uses PHP's magic __get function.
class B {
private $map = array(
'x' => 'A',
'account' => 'ServiceAccountType'
);
private $vars;
public function __construct() {
$this->vars = array();
foreach ($this->map as $var => $class) {
$this->vars[$var] = new $class;
}
}
public function __get($v) {
return $this->vars[$v];
}
}
Notice that you don't need to define the class members twice using this method.