class SubObject
{
static $static_a= 0;
public $normal_a=0;
public function __construct() {
++$this->normal_a;
++self::$static_a;
}
}
$obj1 = new SubObject();
print_r($obj1);
result is :
SubObject Object
(
[normal_a] => 1
)
My question is that why its not display output as:
SubObject Object
(
[normal_a] => 1
[static_a] => 1
)
Does static properites does not exist into the object ? Static variable or property are the way to preserver value of the variable within the context of different instance?
The static properties are attributes of the class (all instances), not an attribute of a specific instance. Here's another class ...
class Dog {
public static $species = 'mammal';
public $furColour;
public function __construct($furColour) {
$this->furColour = $furColour;
}
}
$myDog = new Dog('brown');
All dogs are mammals, in other words the entire "class" of dogs are mammals, so it makes sense to store the $species attribute at the class level (not in every instance of the class). Not all dogs have the same fur colour, that is an attribute of a specific instance of the class know as "Dog".
So, as decided by whoever designed the print_r function, it only prints attributes specific to the instance, not all the attributes of the entire class (or set of all instances). This design decision makes sense. Especially for classes that, for example, define 10's or even 100's of attributes to be used a constants: you don't want to see all these every time you print_r to debug.
FYI, if your app has a real need to get the static values, I think this works
print_r( (new ReflectionClass('SubObject'))->getStaticProperties() );
SubObject Object
(
[normal_a] => 1
[static_a] => 1
)
normal_a and static a are properties.when you dump an object it returns properties and their values.
Related
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.
Hi world genius of programming. I am quite newbie in PDO and OOP, Please understand.
I try to do the most simple thing in the world - get data from a table in MySQL.
I want to:
1) SELECT * from ... it's about 20 fields.
2) To get an array of object with 4-6 of properties.
3) I want to use fetchAll and FETCH_CLASS...
PDOStatement PDO::query ( string $statement , int $PDO::FETCH_CLASS , string $classname , array $ctorargs )
I've found that we can pass an array of argument but can't implement it.
So what am I doing?
class handler{
connection etc..
public $params = array('surname','id','country','display' );
return $stmt->fetchAll(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'person',$this->params);
class person {
public $surname=null;
public $id=null;
public $country=null;
public $status=null;
and then
__construct ()
i will not put it - cause i ve got 50 variants of them(((
}
So, I need to filter options from 20 fields fetching a class but not in SELECT mode instead of *...
Is it possible?
I know that you are genius!
Forgive for newbieness
UPDATE
function __construct($surname,$id,$country,$display) {
$this->surname=$surname;
$this->country=$country;
$id->id->$id
// that the only i need in this oblject
}
function __construct() {
$arg=array('surname','id');
foreach ($arg as $val) {
$this->{$val}=$$val;
}
}
it seems it maybe the next.. not construct function that will filter properties...
UPDATE
I tried solutions as #GolezTrol kindly proposed.
Solution 1 is arguing for... Notice: Undefined property: Person::$_attributes in
if i make
class Entity {
public $_attributes;
function __construct() { ....
or
class Person extends Entity {
public $_attributes;
}
it works.. but i get an object...
[0] => Person Object
(
[_attributes] => Array
(
[0] => surname
[1] => id
[2] => country
[3] => status
)
[id] => 298
.. it's not good(
I think you mean that you want to load only the properties that you specified instead of all values that were returned from the query. Your attempt is to do that by passing the desired field names to the constructor.
Solution 1: Just specify the array of properties and block the rest
Your way might just work, if you get a little help from the __set magic method. Using func_get_args() you can get all the arguments of a function (the constructor in this case) into an array. This way, you get the array of field names that you passed to fetch_all.
The magic setter only sets the properties if they exist in the array that was given to the constructor, so essentially it filters out all fields you don't want.
Advantage: easy. No specific implementation needed in descendant classes. You could just use Entity as a class for all entities.
Disadvantage: magic setter is called for every property and calls in_array this may be slow. fetch_all is determining which fields to read, while maybe this should be the class's responsibility.
class Entity {
function __construct() {
$this->_attributes = func_get_args();
}
function __set($prop, $value) {
if (in_array($prop, $this->_attributes)) {
$this->$prop = $value;
}
}
}
// If you would need a descendant class to introduce methods, you can..
class Person extends Entity {
}
$stmt->fetchAll(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'Person', array('id', 'surname', 'gender'))
Solution 2: block all properties that don't exist
Similar solution, but much cleaner, I think. Implement the magic setter and make it do... nothing. It will be called for properties that don't exist and only for properties that don't exist. So in Person you just declare whatever values you want to read. All other properties will be directed to the empty __set method so they are implicitly ignored.
Advantage: Still easy. Hardly any implementation. You can put the empty method in a base class or just implement it in Person and every other class you have. You just declare the properties in Person. You don't even need to specify the fields you want to read in fetch_all. Also, reading into existing properties is faster.
Disadvantage: if you want to read different sets of information into the same class, this is not possible. The person in my example below always has an id, surname and gender. If you want to read for instance id only, you have to introduce another class. But would you want that?..
class Entity {
function __set($prop, $value) {
// Ignore any property that is not declared in the descendant class.
}
}
class Person extends Entity {
public $id = null;
public $surname = null;
public $gender = null;
}
$stmt->fetchAll(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'Person')
Solution 3: Read only the fields you want
This is actually the best solution. Instead of selecting all fields, SELECT *, select only the fields you want to have: SELECT id, surname, gender ... This way, you won't have objects with too many values, but more importantly, you also decrease the load on your database. The database doesn't need to fetch the data, PHP doesn't need to receive it, and if the database server is separate from the webserver, you also save network traffic. So in all regards, I think this is the best option.
As you can see below I have a super class (Article) and two sub classes. I want each of the sub classes to have a static array that shall hold all it's objects.
abstract class Article
{
public static $articles = array(); // Variable for storing all the objects of each sub-class.
public function add_Object_To_Array()
{
array_push(self::$articles, $this);
}
}
class Report extends Article{}
class Interview extends Article{}
-Making two Report objects and adding them to their array:
$tmp = new Report();
$tmp->add_Object_To_Array();
$tmp = new Report();
$tmp->add_Object_To_Array();
-Making two Interview objects and adding them to their array:
$tmp = new Interview();
$tmp->add_Object_To_Array();
$tmp = new Interview();
$tmp->add_Object_To_Array();
print_r(Report::$articles);
print_r(Interview::$articles);
-The above script spits out the two arays:
Array
(
[0] => Report Object()
[1] => Report Object()
[2] => Interview Object()
[3] => Interview Object()
)
Array
(
[0] => Report Object()
[1] => Report Object()
[2] => Interview Object()
[3] => Interview Object()
)
Which looks pretty similar if you ask me, but the first one should only contain Reports, and the second one only Interviews.
1. It seems that there is only one array, why is it only one array?
2. I have a static container of objects in the same class, is this bad coding? (Any suggestions?)
I'm pretty new to php, but have a background from java.
Everything is going into only one array for two reasons:
The $articles property is only defined in the Article class.
Static class properties do not get inherited the same way you might expect if you're used to non-static properties. While they are available to the child classes, they're still referencing a single variable on the parent class - resulting in the behavior you're seeing here where both child classes are sharing the same array.
The only way to prevent this is to define a separate array in each of your child classes, like this:
class Report extends Article {
public static $articles = array();
}
class Interview extends Article {
public static $articles = array();
}
This actually makes sense if you think of the static variable declarations as code that gets run when the class is defined. Creating a static variable and assigning an empty array to it happens when the Article class is defined. It doesn't happen again when the Interview and Report classes are defined. There's only one time that an empty array is getting assigned - there's only one shared variable.
You're using self in your add_Object_To_Array() method instead of static.
self:: refers to the class it is defined in, so since your add_Object_To_Array() method is defined in the Article class, it'll refer to the Article::$articles array.
static:: Is available starting in PHP 5.3, and refers to the class it is called on. This is known as Late Static Binding, and will result in add_Object_To_Array() referring to either Report::$articles or Interview::$articles depending on the type of the object you're calling it on.
This code will reference the two arrays that we declared in the first step:
public function add_Object_To_Array() {
array_push(static::$articles, $this);
}
I thought I'd present an alternate solution that changes your design slightly, but doesn't require static definitions in each subclass. Depending on your usage, this may or may not be a better option than the first solution.
This solution uses get_class() to find the type of the object we're storing, and then stores it in the parent class - in a sub-array keyed by classname:
abstract class Article
{
public static $articles = array();
public function add_Object_To_Array()
{
// get the actual class of the current object
$class = get_class($this);
// define an empty subarray for this class if we haven't seen it before
if (!isset(self::$articles[$class])) {
self::$articles[$class] = array();
}
// add this object to the appropriate subarray
array_push(self::$articles[$class], $this);
}
}
class Report extends Article{}
class Interview extends Article{}
The above code does not use late static binding, so it'll work with any PHP version, instead of just PHP 5.3+.
When you run this version with your original example, you'll get output like this:
Array
(
[Report] => Array
(
[0] => Report Object
(
)
[1] => Report Object
(
)
)
[Interview] => Array
(
[0] => Interview Object
(
)
[1] => Interview Object
(
)
)
)
If you do have PHP 5.3 or later, you can extend this even more and use the get_called_class() function to define a getInstances() static method (in the Article class) that works like this:
public static function getInstances()
{
$class = get_called_class();
// return isset(self::$articles[$class]) ? self::$articles[$class] : array();
if (isset(self::$articles[$class])) {
return self::$articles[$class];
} else {
return array();
}
}
Then you can call this method in your example like this:
print_r(Report::getInstances());
print_r(Interview::getInstances());
What I would like to do is have a static factory function that you can give a series of attributes and it returns an object that is of a previously undeclared class that extends a known class.
Basically:
<?php
class foo {
public $a;
function increment($b = 1){
$this->a += $b;
}
}
function factory($name, $a){
//returns an object of class $name that extends foo with $this->a set to $a
}
so that if I write the code:
<?php
$bar = factory("bar",12);
$bar->increment(5);
print_r($bar);
if(is_a($bar, "foo")){
echo "is a Foo";
}
$moo = factory("moo", 4);
$moo->increment();
print_r($moo);
if(is_a($moo, "foo")){
echo "is a Foo";
}
I get: [edit]
bar Object
(
[a] => 17
)
is a Foo
moo Object
(
[a] => 5
)
is a Foo
But I don't know where to start looking for the commands necessary to do this. I think that in my factory function I need to somehow declare that the value of $name extends parent class but makes no changes to it, then constructs a new $name. That way it has all the functionality of the parent class, just a different type.
Check out the PHP reflection API has the methods you need to extract and build the new class there but, how to go about doing it and then creating an instance of it im not sure of. I do know its possible though because im pretty sure this is how Mocking works in PHPUnit. You might also want to look at the various Mock object related classes in PHPUnit to get some ideas as well.
That said unless you are actually adding/overloading methods, why would you even want to do this? Why not just use a property in the object or use a an interface? Whats the goal here?