How handle visibility change of property in class when using serialized objects? - php

UPDATE:
As someone says this question is a bit unclear. I couldn't really understand it myself. But I did dig up the solution. It's a PHP bug that has been resolved. The server this legacy code runs on has an outdated php version.
Old code:
class MyChildClass extends MyBaseClass
{
protected $myProp = "foo";
}
class MyBaseClass {
}
$myObject = new MyChildClass();
$myObjectS = serialize($myObject);
New code:
class MyChildClass extends MyBaseClass
{
}
class MyBaseClass {
public $myProp;
}
// $myObjectS is the same as in the Old code above.
$myObject = unserialize($myObjectS);
This will result in an object with a protected property $myProp with a value of "foo". But there will also be a public property with the same name with an undefined value.
I really do not know how to fix this. The result I want is to have the objects public property populated with the serialized objects value for its protected property.
I would not design the code like this with the serialization of complete objects. But this is a legacy project where I (for the time being) have to deal with this.

Not easy as you'll have to change all the occurencies of protected properties in $myObjects.
In your example {s:7:"*myProp";s:3:"foo";} become {s:6:"myProp";s:3:"foo";}.
Set length of myProp from 7 to 6, and remove the leading star of *myProp. Lot of work if you have lot of protected properties :/

Related

Testing setting a private property: can we use the mock to set the value and reflect the property to check if value was set?

I have both a "way of doing this" and "how is it done" question(s).
Class realClass {
private $privateProperty;
public function __construct($someArray, $someString) {
// stuff
}
public function setProperty($someArray) {
$this->privateProperty = $someArray;
}
}
class testRealClass extends TestCase {
// creating a mock because don't want to have tests depending on arguments passed to the constructor
public function setUp(): void
{
$this->classToTest = $this->getMockBuilder(realClass::class)
->disableOriginalConstructor()
->setMethods(null)
->getMock();
}
// testing the set of the variable. In order to know if it was set, without using a getter,
// we probably need to use reflection
public function testSetPrivateProperty() {
$this->classToTest->setProperty([1,2,3]);
// This will not work as the property is private
// echo $this->classToTest->privateProperty;
// Reflecting the mock, makes sense? How does this work?
$reflect = new \ReflectionClass($this->classToTest);
$property = $reflect->getProperty('privateProperty');
$property->setAccessible(true);
var_dump($property->getValue($this->classToTest));
}
}
When executing this I get a ReflectionException: Property privateProperty does not exist.
If I do a print_r of the reflections->getProperties I can see the property there.
I understand this would be easily achievable with just a getter in the realClass but take this as an exercise.
Doest this make sense at all or this will not work because it is just wrong?
Thank you everyone
(Wrote the code here so if I'm missing ";", "(", etc, do ignore it :)
Using Reflection API for testing is seldom a good idea. However, the real question is - why have a private property if nothing can access it? Obviously, the property is used in another method of the class. So, the clean solution here is remove all reflection code, then create a getter in the class itself, and replace all calls to $this->property to $this->getProperty(), then you can easily test this.
For a more generalized take on this question, private properties and methods are not meant to be tested, they are private because they conceal their data from everyone, including the tester classes. The more private fields and properties your class has, the less testable it gets, so when this becomes a hindrance, it is better to split the class into two, making one of the private methods public.

How can protected property of a class be visible from a static method in PHP?

I understand OOP. What I understand so far is that private and protected cannot be referenced from outside the class using $this->blah notation. If that is correct, how can the following code work?
<?php
class test {
protected $a = "b";
public static function oo(){
$instance = new static();
echo $instance->a;
}
}
test::oo();
Gives me an output of b! Now, how in Lord's name can that happen?
In PHP 5.3, a new feature called late static bindings was added – and this can help us get the polymorphic behavior that may be preferable in this situation. In simplest terms, late static bindings means that a call to a static function that is inherited will “bind” to the calling class at runtime. So, if we use late static binding it would mean that when we make a call to “test::oo();”, then the oo() function in the test class will be called.after that you return $instance->a; static keyword allows the function to bind to the calling class at runtime.so if you use static then whatever access modifier(private,public,protected) you use it's just meaning less...
please read this link,another
That happens because you're "presenting it" by echo'ing it. You can't reference it like this for example:
class test {
private $a = 'b';
function __construct() {
echo 'instantiated';
}
}
$test = new test();
echo $test->a; // This line won't work, since it's a private var.
It would give you an error message that looks like this:
Fatal error: Cannot access private property test::$a
Example (https://eval.in/226435)
As I said before, you're accessing it from within the class itself, so you CAN view it. (That's the $instance you have there.) If you modify your code to use it like this:
class test {
protected $a = "b";
public static function oo(){
$instance = new static();
return $instance;
}
}
echo test::oo()->a;
Example of the above (https://eval.in/226439)
You'll get that "private acess blah blah" error.
You're understanding the statement wrong. "private and protected cannot be referenced from outside the class" means that as the examples above show, you CAN NOT access the variables outside the class, but with your example, you're accessing it from INSIDE the class, which means they'll do as you require (echo'ing out as you did)
What I understand so far is that private and protected cannot be referenced from outside the class
As follows, since oo is defined in the same type as a, oo has access to a.
This is actually a very good question, and shouldn't be down-voted.
From what I understand, the reason why you can access a protected/private property from within a static method of the same class, is because "the implementation specific details are already known when inside this class". I rephrased this a little from what is documented on the official page on Visibility:
Objects of the same type will have access to each others private and protected members even though they are not the same instances. This is because the implementation specific details are already known when inside those objects.
This makes sense. Visibility access is meant to only expose things that are safe for the public to use. But if you already have access to the code of the Class you're using, then there is no point of preventing you to use what you already see. Hope that makes sense..

Create a Collection of Objects from a Class Using a Transformer Function

In this question I would like to discuss a problem related to building a collection of homogeneous objects from a class using a transformer function that transforms a passed array or other sort of collection. The problem lies in the fact that I want to be able to see from which class are the objects in a collection when doing the transofrmation and at the same time avoid using statics as we all know they are kind of tricky and the general recommendation is to avoid them.
The scenario is the following:
There is an abstract class that does some common parsing of data (formatting dates, strings, floats, etc.) called AbstractData. Its purpose is to be extended by more concrete classes which make use of the abstract functions and hold the parsed data.
The concrete class uses a mapping array which tells how given raw data has to be parsed using the functions from the abstract class.
Currently what is being done to create a collection of such concrete class objects is the following (take care that the constructor of the Concrete class takes single row of data which it parses automatically using the defined mapping scheme):
collection = [];
foreach($rows as $row) {
collection = new ConcreteClass($row);
}
What I have here basically is just an array of those objects, but I was wondering what would be the best way to keep a more structured collection the same way you could do using generics in Java like List<ConcreteClass> collection = new List<ConcreteClass>(row);
Right now what I did was to make a static "factory" function in the abstract class:
public static function factory($data = null) {
return new static($data);
}
And a function that creates the "processed" collection:
public function createCollectionFromRawData($rows) {
$collection = [];
foreach($rows as $row) {
$collection[] = new static($row);
}
return $collection;
}
And call the concrete class like this: ConcreteClass::factory()->createCollectionFromRawData($rows)
And although it allows for better reading in a way it is a bit redundant since it does not separate concerns and additionally I have to create an empty object of the ConcreteClass just to be able to invoke the non-static createCollectionFromRawData function which I would like to avoid doing.
I was thinking something in the lines of involving DI to solve the problem but I am not really sure what exactly I can do.
I don't see the harm in using the late static binding functions I use them heavily in an ORM i have written but i do record the class name in a var on the class at each level because I have needed it for some tasks. I think you are trying to get a collection of items dependent on what you class you statically give the factory? Here is my crack at solving what I think you are asking. I do this by always using the public method on the abstract class, and defining the protected method on the class you are building as each of these may handle the input differently.
abstract class AbstractData {
protected $_abstractClassData;
public static final function factory($rawData)
{
return static::_createCollectionFromRawData($rawData);
}
}
class ConcreteClass extends AbstractData {
protected $_concreteClassData;
protected static function _createCollectionFromRawData($rows) {
$collection = array();
foreach($rows as $row) {
$collection[] = new static($row); //If you havnt defined a constructor on this class it will use your AbstractData one.
}
return $collection;
}
}
$collection = ConcreteClass::factory($rawData);

$this->class->function(): how does it work?

I've been programming in PHP for several years and I've only just recently begun to look at object oriented code. Now I understand classes and such:
class Myclass {
public function __construct() {
}
}
and all that good stuff... I also understand creating functions and calling in my index.php:
$someVar = new Myclass;
One thing I've been trying to understand, being that i've recently looked at codeigniter and I like one thing about it and want to try and accomplish the same thing without actually using codeigniter.
in code igniter they have the variable $this appear to be their class variable. But by using that, you're able to call from multiple classes all at once.. such as:
$this->load->module(); which is in one class file..
$this->db->query(); which is in another class file.
I've searched google for the last few days trying to figure out how to do this same thing where each class would have the correlation between them all allowing me to run $this->class_name->function_name in my projects instead of creating a new variable for each class or for the sake of a clean index file, having every function in a single class file.
Any information (aside from buy this book - as that isn't an option for me) is greatly appreciated and I will thank you now (and will probably thank you again later just for good measure).
I've been reading you and Phil's comments. First off, you can't use $this on index.php. $this can only be used in the context of an object. So you could do,
$someVar = new Myclass;
...
$someVar->db->something();
...instead.
I'm not entirely sure what you mean by "read classes," but you can assign members to MyClass exactly as Phil indicates:
class MyClass {
private $inj;
function __construct(Injected $inj) {
$this->injected = $inj;
}
}
Note that the private $inj declaration is not mandatory, but skipping it is dangerous. Any non-declared members added are automatically public, and this can potentially screw with you if you rely on magical get. I would declare the properties you need.
Finally, you either need to include all class definitions you will use, use a function like load_class(), or use autoloading. If Injected above is not a declared class, you will get an error when trying to create one. load_class() almost certainly includes the class definition somehow.
The load and db references are class properties which are themselves other objects with public module() and query() methods respectively. For example
class MyClass
{
/**
* #var CI_DB
*/
private $db;
/**
* #var Loader
*/
private $load;
public function __construct(CI_DB $db, Loader $load)
{
$this->db = $db;
$this->load = $load;
// PHP also allows you to add arbitrary object properties
// that receive a "public" visibility
// Please note, this is not a good practice
$this->foo = new Foo;
}
public function someMethod()
{
$this->load->module();
$this->db->query();
// You can also use foo even though it is not defined
// in the class properties
$this->foo->something();
}
}
See http://www.php.net/manual/en/language.oop5.properties.php
Adding the foo property like we did is dangerous. Because it receives the public visibility, it may be altered externally to the class.
$class = new MyClass($db, $load);
$class->foo = new Bar;
$class->someMethod(); // will break if Bar does not contain a something() method

PHP Scope and Class Instance Interaction

It seems as though different instances of a class can know about each others' private member variables.
I have provided some code that attempts to showcase my issue, and I will try to explain it.
We have a class with a private member variable, $hidden. modifyPrivateMember sets the value of $hidden to 3. accessPrivateMember takes an Object as a parameter and accesses its private $hidden member to return its value.
Example code:
<?php
// example.php
class Object {
private $hidden;
public function modifyPrivateMember() {
$this->hidden = 3;
}
public function accessPrivateMember(Object $otherObject) {
return $otherObject->hidden;
}
}
$firstObject = new Object;
$firstObject->modifyPrivateMember();
$otherObject = new Object;
echo $otherObject->accessPrivateMember($firstObject);
Output of the above code:
$ php example.php
3
Can anyone explain why private members of objects are accessible to other instances of the same class? Is there some justification for this ostensible breach of scope?
private means it's restricted to only that class, not only that object.
That's just how php works. It's the same as how Java works. See http://php.net/manual/en/language.oop5.visibility.php for more info.
The only situation in which this behavior seemed useful was in a factory function:
class Object
{
private $state;
public static function makeObject()
{
$obj = new Object;
$obj->state = 'some state';
return $obj;
}
}
Even in this case, there are better solution and I agree with you that it is a breach of scope, although not that big in my opinion. After all, the one who writes the class decides if she needs to access private members from objects passed as arguments. So, it may seem useless (even to me), but you never know. It's not like you're exposing your internals to subclasses or something. It all happens in the same class and it's your business what you're doing in there.
By the way, one language that implements access modifiers per object and not per class is Ruby.

Categories