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

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.

Related

Use parents child method in other child class (same parent)

I have some issues with OOP. I just started OOP in php and i have some issues.
So i have a question for you, maybe you'll help me.
I have multiple classes (in this case 3)
<?php
//FILE class.NB.php
class NB { //databse manipulations, curls
public $db;
function __construct($db) {
$this->db = $db;
}
public function LoginNB () {
//something here
$this->db->query("UPDATE logins SET login_time = %u", time());
}
}
//FILE class.fn.php
class FN extends NB {
public function deposits () {
$this->LoginNB();
return $this->db->query("SELECT * FROM deposits");
}
public function getUserWihdrawsCompared() {
// AND HERE I WOULD LIKE TO USE the DR's ::usersWithdraws
$users = $this->usersWithdraws();
}
}
//FILE class.dr.php
class DR extends NB {
public function withdraws () {
$this->LoginNB();
return $this->db->query("SELECT * FROM withdraws");
}
public function usersWithdraws() {
$a = $this->db->query("SELECT * FROM user_withdraws");
/*code here*/
return $final_array;
}
public function compare_withdraws_deposits () {
// AND HERE I WOULD LIKE TO USE the FN's ::deposits
$deposit_list = $this->deposits();
/* code here */
return $final_array;
}
}
?>
So my question is, how is possible to use everything in everywhere.
I saw something with traits but i'm not sure, how to use and what exactly to use.
My problems is what i want to user parent's child method in other child with same parent.
But in the end, i would like to use only the parent class for "runing" implementing in other classes if it's possible.
Like:
$NB = new NB($db);
$result = $NB->ShowResults();
Problem: ShowResults() should use both child's methods and child methods used in ShowResults() some times use methods from other child class.
Maybe it's impossible but i would appreciate if you could help me. (even with a confirmation that is not possible)
Thank you.
I think you haven't fully grasped what we mean by "parent" and "child" in OOP, and why they're useful. The purpose of inheritance is not to grant access to the methods of one class in another, or to automatically run multiple implementations of the same thing. Instead, the purpose is to allow code outside the classes to call one of the implementations without needing to know which one.
So, if I have an instance of class NB, I know I can call LoginNB on it. If what I'm passed is actually an instance of class FN, that will still work; class FN will either inherit that method, or reimplement it a different way, but with the same external signature.
However, class NB doesn't know anything about what classes inherit from it, any more than a function knows where else it is called from; the relationship only goes one way.

Passing an object between different classes?

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;
}
}
?>

PHP get child class methods

Is it possible in PHP to get the methods of an extended child class in a method declared in the parent class?
Here is a simple (maybe stupid) example:
<?php
class Vehicle{
protected function moveForward(){
// go ahead...
}// moveForward
public function getWhatCanIDo(){
$actions = get_class_methods($this);
return 'I can '.implode(', ', $actions).'<br/>';
}// getWhatCanIDo
}
class Car extends Vehicle{
protected function honk(){
// honk...
}// honk
protected function turnHeadlightsOn(){
// turn headlights on...
}// turnHeadlightsOn
protected function stopEngine(){
// stop the engine
}// stopEngine
}
class Submarine extends Vehicle{
protected function submerge(){
// sink...
}// submerge
protected function ping(){
// ping...
}// ping
protected function fireTorpedos(){
// DESTROY!!!
}// fireTorpedos
protected function stopEngine(){
// stop the engine
}// stopEngine
}
$volvo = new Car();
$uboat = new Submarine();
echo $volvo->getWhatCanIDo();
echo $uboat->getWhatCanIDo();
?>
The output what I expect is:
I can moveForward, getWhatCanIDo, honk, turnHeadlightsOn, stopEngine
I can moveForward, getWhatCanIDo, submerge, ping, fireTorpedos, stopEngine
But instead It returns the the methos of the Vehicle class only, without the methods implemented in the extended class:
I can moveForward, getWhatCanIDo
I can moveForward, getWhatCanIDo
How could I get the extanded class methods?
Additional Infos:
I have to solve this in PHP 5.2.14
The extended classes will have different numbers of methods with different method names so making Vehicle an abstract class wont help, because e.g.: I dont want Submarine to have honk method.
I know I could make the getWhatCanIDo() an abstract method, but I'd like to implement this method "centrally" in the parent class, I dont want to oblige developers to write getWhatCanIDo() method for every extended class (In the future others may join or continue this project, and Its more failsafe to not let them implement this method again and again especially when the method does exactly the same thing.)
You should declare class Vehicle abstract, because it does not really exist and the real vehicles implement it.
Then put whatCanIDo in Car and in Submarine, because you don't ask the vehicle what it can do, you ask the car.
class Car extends Vehicle{
public function getWhatCanIDo(){
$actions = get_class_methods($this);
return 'I can '.implode(', ', $actions).'<br/>';
}// getWhatCanIDo
}
Update:
A yet different approach is to use the standard PHP library ReflectionClass:
$class = new ReflectionClass('Vehicle');
$methods = $class->getMethods();
You need to overload the getWhatCanIDo() function in the Car & Submarine classes. You get the output because the function is executed in the Vehicle class.
Overloading the method causes it to be executed in either the Car or Submarine class.
You could also try get_class_methods(); More at http://www.php.net/manual/en/function.get-class-methods.php
This code is not tested, please, let me know if it works.
class MyBaseClass {
//...
public function getMethods($className) {
return get_class_methods($className);
}
public static function getMethods($myObject) {
return $myObject->getMethods(get_class($myObject));
}
//...
}
class MyInheritedClass {
//...
}
$myBaseObject = new MyBaseClass(/*...*/);
$myInheritedObject = new MyInheritedClass(/*...*/);
echo var_dump(MyBaseClass::getMethods($myBaseObject));
echo var_dump(MyBaseClass::getMethods($myInheritedObject));
Inheritance is not proper tool here. You should use composition. Example:
Have separate objects Runner, Swimmer, WorkWithEngine, Submerge. All off them implements interface with getWhatCanIDo() method.
Create your new Vehiclas by composing them from Types from point one. This object implements interface with getWhatCanIDo() method as well.
$submarine = new Submarine();
$submarine->addAblility(new Swimmer());
$submarine->addAblility(new WorkWithEngine());
$submarine->addAblility(new Submerge());
$submarine->whatCanIDo();
In any case do not use magic like get_class_methods those are constructs for frameworks creators it is not stuff for coding business logic.

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.

Static variable assignment in descendent bubbles up to parent?

I've run into a problem and I'm not sure if this is just normal behaviour or if I wrote something wrong. I have a method in my base class that applies a global filter to a given class by way of creating a proxy for all new instances of that particular class. The way I planned to go about it is as follows:
Attach static $global_filter (the proxy) to the class I want to be filtered, which extends the base class object
Via my loading mechanism, return the proxy instead of the actual class upon new instantiations (which will mask method calls and apply filters accordingly)
However, I am getting stuck in step 1 and it seems that when I try to assign static $global_filter to the descendent class I want filtered, my base class object also gets the same assignment, which breaks everything else that extends from it.
Please see below for relevant code:
class object {
public static $global_filter;
public function _filterGlobal($class, $method, $callback) {
if ( !is_object($class::$global_filter) ) {
$class::$global_filter = new filterable(null);
# Replace the object being called with the new proxy.
}
var_dump($class);
var_dump($class::$global_filter); // `filterable`
var_dump(\core\blueprint\object::$global_filter); // Returns same as line above
die();
return $class::$global_filter->_add($method, $callback);
}
}
Both $class::$global_filter and \core\blueprint\object::$global_filter (the base class) are returning same instance. Whereas I expected object::$global_filter to be null.
I'm not using late static binding in order to preserve consistency (both single-object filters and global filters are called much in the same way non-statically).
This question seems relevant
Any help will be much appreciated :)
Edit, full example
This would be a concrete class, which extends model which extends object
<?php
use core\blueprint\model;
class modelMock extends model {
protected $schema = array();
public function method($test) {
return $test;
}
}
This would be another object (e.g a controller), which extends object aswell. It applies a filter to all new instances of model
<?php
use core\blueprint\object;
class objectMock extends object {
public function applyFilters() {
$this->_filterGlobal('core\blueprint\model', 'method', function($self, $chain) {
$chain->params[0] = 'new param'; // adjust the paramters
return $chain->next();
});
}
}
when I try to assign static $global_filter to the descendent class I want filtered, my base class object also gets the same assignment
Yes, indeed this happens. A static property in essence is a global variable, constrained within the class's namespace. Running into problems with global variables is often an indication you're not using the best solution.
To solve your problem, you could make the filter a (non-static) property:
$class->$filter = new Whatever();
But as always, there's more roads that lead to Rome, and I would advise you to look for alterative ways to do it.
I don't know if this is a help for you:
class a {
public static $type;
public static function setType($class, $newType) {
$class::$type = $newType;
var_dump($class::$type);
}
}
class b {
public static $type = 'myType';
}
var_dump(b::$type);
a::setType('b', 'yourType');
var_dump(a::$type);
May be you have not defined the static property to the concrete class.
Thanks everyone for you help, I spent some time on it this morning and managed to solve my problem. It's a bit of a workaround but here's how it goes:
public function _filterGlobal($class, $method, $callback) {
if ( !is_object($class::$global_filter[$class]) ) {
$class::$global_filter[$class] = new filterable(null);
# Replace the object being called with the new proxy.
}
return $class::$global_filter[$class]->_add($method, $callback);
}
So basically in order to get unique static variables working in child classes without having to explicitly define them, you can use an array that stores the child's class name as a key and then access these variables via a getter.

Categories