Passing an object between different classes? - php

I've always passed data manually between different classes. So for example I had some data produced by one class:
$someData = $Object->someMethod();
$moreData = $Object2->anotherMethod($someData);
But it feels clunky to me and it results in messy code that gets complicated. Especially if there are multiple different kinds of data passed around multiple classes.
So instead of doing that I've decided I will create a class DataContainer that groups every variable related to the process and then I will just pass this object around different classes. As it passes the processing pipeline, it will gather more and more data until almost every of its field is set to some value.
So for example I have a pipeline of processing data that gets modified by 4 different classes - instead of passing the data by value I will pass it by reference:
$myObject = $class1->method1(); // this class returns the DataContainer object
$class2->method2($myObject);
$class3->method3($myObject);
$class4->method4($myObject);
Is it considered a better choice? Or is there something better?

Keep in mind to make your code SOLID. (http://en.wikipedia.org/wiki/SOLID_(object-oriented_design))
In your case, you can create in the constructor of class2 a reference.
For example:
<?php
class Class1
{
private $class2;
public __construct(Class2 $class2)
{
$this->class2 = $class2;
}
public function CallMethodOfClass2()
{
$value = $this->class2->GetMethod();
$propertyValue = $this->class2->public_property;
}
}
?>
Or when your Class2 cant exists without Class1, make in the constructor of Class1 a new instance of Class2 like this:
<?php
class Class1
{
private $class2;
public __construct()
{
$this->class2 = new Class2();
}
public function CallMethodOfClass2()
{
$value = $this->class2->GetMethod();
$propertyValue = $this->class2->public_property;
}
}
?>

Related

Property VS reference: share a variable between class methods

Let's say that I'm building a class (for a generic purpose) and I have two methods that work on common variables.
class renderElement
{
public function process()
{
$output = array();
$data = $this->supportMethod($output);
// do stuff with $output
}
public function supportMethod(&$processed_output)
{
// do stuff with $processed_output
}
}
I want to use the same variable into both methods; let's say $output.
I'm curious to know the theory behind the choice of eventually rely on a class property (like following) or when instead is ok (or better) to pass the variable as reference.
class renderElement
{
private $output = array();
public function process()
{
$data = $this->supportMethod();
// do stuff with $this->output
}
public function supportMethod()
{
// do stuff with $this->output
}
}
Advantages? Disadvantages? Design suggestions?
Suggested lectures about this kind of design choices?
[ EDIT ]
I would add that the variable/property should obviously have sense as an object property. I'm not talking about variables for just supporting data processing.
An object fundamentally consists of two things, behaviour and state.
Methods of your class define the behaviour of your object.
Attributes of your class define the state of your object.
In your first example, $output isn't a part of the object's state, so it will not persist throughout the life of the object.
In your second example, $output will persist throughout the life of the object since it is a part of the object's state.
Take this example...
class Shape
{
protected $sides;
public function getNumberOfSides()
{
return $this->sides;
}
}
class Triangle extends Shape
{
public function __construct()
{
$this->sides = 3;
}
}
class Square extends Shape
{
public function __construct()
{
$this->sides = 4;
}
}
$shape = new Square;
echo $shape->getNumberOfSides(); // Returns 4
$shape = new Triangle;
echo $shape->getNumberOfSides(); // Returns 3
$sides (number of sides) is an intrinsic part of a shapes nature, therefore it is appropriate for it to be a part of the object's state throughout the life of the object. This doesn't really have anything to do with the convenience of passing parameters between methods in the same class.

PHP OOP - Pass data between classes through the calling class?

I'm struggling to find a correct approach to pass data between classes, which do not directly call each other, and are only related through a parent class (which I now use, but I consider it a dirty workaround rather than anything near a solution).
I have 3 classes both able to read input and write output, and based on configuration I set one to read, another one to write. It may even be the same class, they all share a parent class, but they are always two separate instances called from a controller class.
Currently I use this sort of functionality:
class daddy {
public static $data;
}
class son extends daddy {
public function setData() {
parent::$data = "candy";
}
}
class daughter extends daddy {
public function getData() {
echo parent::$data;
}
}
while($processALineFromConfig)
$son = new son;
$son->setData();
$daughter = new daughter;
$daughter->getData();
daddy::$data = null; //reset the data, in the actual code $daughter does that in parent::
}
Instantination of these classes runs in a loop, therefore I always need to reset the data after $daughter receives them, 'cos otherwise it would stay there for another pass through the loop.
I'm absolutely sure it's not how class inheritance is supposed to be used, however I'm struggling to find a real solution. It only makes sense the data should be stored in the controller which calls these classes, not the parent, but I already use return values in the setter and getter functions, and I am not passing a variable by reference to store it there to these functions 'cos I have optional parameters there and I'm trying to keep the code clean.
What would be the correct approach to pass data through the controller then?
Thanks!
The best option would be for two object share some other, third object. This would be the class for "third object" which will ensure the exchage:
class Messenger
{
private $data;
public function store($value)
{
$this->data = $value;
}
public function fetch()
{
return $this->data;
}
}
Then a class for both instance, that will need to share some state:
class FooBar
{
private $messenger;
private $name = 'Nobody';
public function __construct($messenger, $name)
{
$this->messenger = messenger;
$this->name = $name;
}
public function setSharedParam($value)
{
$this->messenger->store($value);
}
public function getSharedParameter()
{
return $this->name . ': ' . $this->messenger->fetch();
}
}
You utilize the classes like this:
$conduit = new Messenger;
$john = new FooBar($conduit, 'Crichton');
$dominar = new FooBar($conduit, 'Rygel');
$dominar->setSharedParameter('crackers');
echo $john->getSharedParameter();
// Crichton: crackers
Basically, they both are accessing the same object. This also can be further expanded by making both instance to observe the instance of Messenger.

What is the proper method of structuring PHP classes as Parent Child?

I have the following PHP Classes
class.property.php
class.location.php
class.amenity.php
class.category.php
all four classes handles the respective CRUD operations for different categories. i want to refactor my codes and hence wants to go with the Parent Child Structure.
for example i used to initialize classes on every page like this.
$property = new Property($dbh);
$location = new Location($dbh);
$category = new Category($dbh);
$amenity = new Amenity($dbh);
and then i used to access class methods and properties individually like
$property->user;
$property->contact;
$property->save();
$location->countries();
$location-states();
Andso on, every class is executing indivdually, instead of accessing it like this i would like to use it this way.
$property = new Property($dbh)
above should be the Parent class and rest three child class, and so i should be able to access all class methods and properties only through parent class for example i should only be able to access it like this..
$property->location->countries();
$property->locations->states();
$property->location->countryId;
$property->amenity->name;
$property->amenity->save();
and so on..
i tried to figure out how to do it and came out with this solution.
class Property{
public $amenity;
public function __construct() {
require_once('class.amenity.php');
$this->amenity = new Amenity;
}
}
class Amenity {
public function create($test) {
return $test;
}
}
now if i want to access the create() method in Amenity class i simply call
$property->amenity->create()
and it works, however i would like to know if this is the correct method of implementing the Parent Child Structure or am i missing something?
There is no need for the create() call:
class Property{
public $amenity;
public function __construct() {
require_once('class.amenity.php');
$this->amenity = new Amenity;
}
}
class Amenity {
}
$property = new Property;
$amenity = $property->amenity;
At the very most, you'll want to make the properties protected, and use getters and setters.

OOP/PHP5: Calling Class A from Class B - or, Making the horse jump

Say you have two classes, A and B. Is it possible to instantiate both classes once and then let class B call methods in class A, and vice versa?
It can be done using double colon (::) ... ... but then the method becomes static - is that a disadvantage? (see example below)
Can it be done in other ways? With interfaces?
This code shows what I try to do:
class A {
function horse() {
echo "horse";
}
}
class B {
function jump() {
// $A = new A; ... don't want to add this in each method.
$A->horse(); // Fails - $A is out of scope ($A = new A;).
// A::horse(); // Old code style - works.
// $this->horse(); // Works if you extend A - not self-documenting.
// $this->A->horse(); // Fails - out of scope.
}
}
$A = new A;
$B = new B; // Better to use "$B = new B($A);" ?
$B->jump(); // fails - the horse is sleeping.
Edit
Well, I am building a MVC-framework and I want to re-use code from other classes.
Some real-world examples:
a database object that is being passed across classes.
a "url" class that creates/manipulates URLs - used by other classes.
... and a code example:
class url {
function anchor($url,$name) {
return "{$name}";
}
}
class someclass {
function text($str,$url) {
return "{$str}. " . $url->anchor($url,"Read more...");
}
}
I think what you are asking for is multiple inheritance where you could extend both A and B like this
<?php
class C extends A,B {
//...
}
This however is not possible in PHP for good reasons(it actually is creating more problems than it's trying to solve).
Now you might ask yourself if there is any alternative to multiple inheritance and the answer is: Yes, there is! Have a look at the strategy pattern(as Benjamin Ortuzar also has pointed out).
UPDATE:
I just read your question a second time and figured that you might be looking for the singleton pattern, which lets you instantiate an instance of an class only once like this:
class A
{
protected static $_instance;
protected function __construct() //prohibit creating instances from outside
{ }
public static function getInstance()
{
if( self::$_instance === NULL ) {
self::$_instance = new self();
}
return self::$_instance;
}
}
$instance = A::getInstance();
Now A::getInstance() always returns the same instance of A which you can use in B and you can have both the advantages of dynamic functions and the accessibility of static functions.
UPDATE2:
Your database belongs into a registry if you can have more than one db-connection. If you're absolutely certain that you will always need only one db-connection you could as well make it a singleton.
For the URL helper I'd suggest writing a static class if you can and if you really need it to be dynamic make it a singleton, as mentioned before.
I think that this should work:
$B = new B();
$B->jump();
But you should read/refer to http://www.php.net/manual/en/language.oop5.php
Of course you should import the class if you're accessing it from a different php file. And if you're in the object you're calling the method of you should use
$this->jump();
I would suggest reading about the factory and strategy pattern. You can read more about this from chapter one of this fantastic book. link text
I would recomend you reading the whole book.
Maybe (just guessing) you're looking for something like aggregation in COM:
Aggregation is the object reuse mechanism in which the outer object exposes interfaces from the inner object as if they were implemented on the outer object itself.
You can build something like that with the "magic method" __call. Each time a method is called that isn't callable in the object's context this method is invoked and your code can decide what to do with this call. E.g. it can test if another object that is stored as a property of the "outer" object exposes a method with that name and than call that inner object's method.
class Foo {
protected $inner = null;
public function __construct($inner=null) {
if ( is_null($inner) && !is_object($inner) ) {
throw new Exception('...');
}
$this->inner = $inner;
}
public function __call($name, $arguments) {
// also check http://uk.php.net/is_callable
if ( !is_null($this->inner) && method_exists($this->inner, $name) ) {
return call_user_func_array( array($this->inner, $name), $arguments);
}
else {
// add some error handler here
throw new Exception('...');
}
}
function jump() {
$this->horse();
echo " jumps";
}
}
class Bar {
function horse() {
echo "horse";
}
}
$foo = new Foo(new Bar);
$foo->jump();
This works. But I'd recommend something like that only for quite specific circumstances. The most obvious reason beeing that it's hard to tell from the outside what this object $foo really can and cannot do.

Creating Object instance from Posted data - PHP

What is the best way of creating and populating an Object from values passed in from a form?
If for example, i have a class Car with properties Colour, Model, Make, Year and a method Save, which will either insert or update the record.
I then have a form that has fields for all these values and it is submitted. I want to create an instance of class Car with the posted values and then call the Save method. All good and well.
But what is the best way of assigning the posted values to the objects internal properties. Assuming this is a simplified scenario and the actual situation would have many more properties, making individual Set calls long-winded.
Is it best to simply call the Set method for each one? Or pass in an array to a method (or the constructor) which then calls the Set methods? Or some other way?
Any advice on best practices is appreciated
Cheers
Stuart
If the properties are public:
foreach($_POST as $key => $value)
$obj->$key = $value;
If they require setters:
foreach($_POST as $key => $value) {
$set = 'Set' . $key;
$obj->$set($value);
}
You can use a bit of Reflection magic:
public function loadFromArray($array) {
$class = new ReflectionClass(get_class($this));
$props = $class->getProperties();
foreach($props as $p) {
if (isset($array[$p->getName()])
$p->setValue($this, $array[$p->getName]);
}
}
You can implement this method in a base class and make all yout object inherit from that, so you have this functionality in every object without repeating yourself in any class.
I would implement the magic function __set_state(), as it is intended for exactly this use case. There are multiple benefits of putting the implementation into that method:
It is very well defined, what this function does (It is defined in the PHP docs, in contrast to your own source code)
You can access private members within the function
Objects dumped with var_export() will be automatically reconstructed using this function.
EDIT As requested in the comments:
class A {
private $member = 1000;
public static function test(A $a) {
echo $a->member;
}
}
echo A::test(new A()); // outputs 1000
EDIT Fulfilling another request from the comments:
You cannot know on which class a static method was called unless you are using php 5.3, in which the required feature (late static binding) was introduced. What you can do in emulating get_called_class() by analyzing the current stack (using debug_backtrace()). If you have a working get_called_class() function, you can do the following:
class BaseClass {
public static function __set_state($state) {
$class = get_called_class();
// Assumption: Constructor can be invoked without parameters!
$object = new $class();
foreach (get_class_vars($class) as $member) {
if (!isset($state[$member])) {
// Member was not provided, you can choose to ignore this case
throw new Exception("$class::$member was not provided");
} else {
// Set member directly
// Assumption: members are all public or protected
$object->$member = $state[$member];
// Or use the setter-approach given by Chaos.
$setter = 'set' . ucfirst($member);
$object->setter($state[$member]);
}
}
return $object;
}
}
Well, you can convert the post array to an object in one step...
$mypostobject = (object) $_POST;
echo $mypostobject->Colour;
EDIT: added link to PHP docs. http://uk.php.net/manual/en/language.types.object.php
If you want to do this with your own class of object, then some kind of constructor or function that takes the post array and set up your class would be in order.
class MyCar {
public function __construct($postdata)
{
$this->Colour = $postdata['Colour'];
// etc
}
};
$car = new MyCar($_POST);
In case the object that you're posting may become more complex than a flat list of properties in the future (think nesting, arrays as values etc.), you could first create a JavaScript object on the client side and post it as JSON inside a single parameter. Then you can simply deserialize the JSON string into a PHP object. PHP 5+ has built-in support for JSON deserialization. Using JSON would allow you to be flexible in how complex your object can be.
create a constructor which will take all the attributes
class Car {
// private members …
public function __construct($color, $type, $model, $make) {
// assign your values here
}
// other methods
};
if you are dealing with associative arrays, you can also use a constructor with an array as argument:
public function __construct($car_properties) {}
and then loop your properties with
foreach($car_properties as $property => $value) {
if(isset($value)) $this->property = $value
}
be sure to sanitize/validate your input beforehand! (can’t stress this often enough)

Categories