Wrap/Reuse/Clone a PHP object (code optimization) - php

Imagine two classes which share almost the same exact methods and properties, both extending a parent class, but the differences are minimal.
class fields {
public function __construct() {
global $id;
$this->id = $id++;
}
}
class input extends fields {
public function __construct() {
parent::__construct();
}
public function draw() {
echo '<input>';
}
}
class textarea extends fields {
public function __construct() {
parent::__construct();
}
public function draw() {
echo '<textarea>';
}
}
I'm thinking it would be more efficient to rewrite the textarea class in this psuedo-code fashion:
class textarea extends fields {
public function __construct() {
$this = new input(); // <<------
}
public function draw() {
echo '<textarea>';
}
}
Basically, I'm unsure how this would best be done so that the class acts like the class from the first example.
In essence, I would like to do the following using OOP, but be able to use the object as it can be in the first example above (be able to call the possibly overloaded methods, have different properties, etc.):
function a() {echo '123';}
function b() {a();}
I have just copied the entire class and modify a few lines, but I feel it is wasteful.
Final Answer
Thanks to those people, here is the combined answer with example calls:
abstract class fields {
private static $masterid = 0;
public function __construct() {
$this->id = self::$masterid++;
}
}
class input extends fields {
public $data;
public function __construct($new = '') {
parent::__construct();
if ($new) $this->data = $new;
else $this->data = 'Hello';
}
public function draw() {
echo '<input>'.$this->export().'</input>';
}
public function export() {
return 'ID '.$this->id.' = '.$this->data;
}
}
class textarea extends input {
public function __construct($new = '') {
parent::__construct($new);
}
public function draw() {
echo '<textarea>'.$this->export().'</textarea>';
}
}
$a = new textarea();
$a->draw();
$a = new textarea('World');
$a->draw();
$a = new input('!');
$a->draw();
//Outputs:
// <textarea>ID 0 = Hello</textarea>
// <textarea>ID 1 = World</textarea>
// <input>ID 2 = !</input>

Make the fields class an abstract class, and like Darren suggested, make the 'draw' method a function of the fields class.
Now heres the trick, you want the input class to extend fields, but override the draw method. This will allow you to customize the functionality of that method, and you can still call the parent variation from within it.
Finally, since the textarea class is going to have many similarities to the input class, make textarea extend input. Thereby inheriting the properties and methods of both fields and input.

Make the "fields" class have a draw method:
public function draw($msg) {
echo $msg;
}
Then in the textarea or input class put:
parent::draw("<input>");
This cuts down on the number of methods you have, and can call one method for both types of field.
Also in your "fields" class, change the id code to be like this:
public $id
public function __construct($id) {
$this->id = $id;
}
Then in the subclass:
parent::__construct(1); //Or whatever ID you want
The way you have it, ID is the same value every time you set it, which will result in every subclass of fields having the same id. This way each subclass will have a seperate ID.
Also because I'm nice, here's it all put together:
public class field {
$id;
public __construct($id) {
$this->id = $id;
}
public function draw($msg) {
echo $msg;
}
}
public class input extends field {
public __construct() {
parent::__construct(1);
parent::draw("<input>");
}
}
public class textarea extends field {
public __construct() {
parent::__construct(2);
parent::draw("<textarea>");
}
}
That's how I'd put it together from what you've said. I may have mistaken what you were asking for though. Can you tell I'm primarily a Java programmer from that?

It's not exactly clear what you want to do. For the example you've given, I think the structure is OK, but you should make a few changes, particularly with the constructor. I think the constructor should be abstract, with an abstract method draw().
abstract class fields {
// Use a static member to keep track of id's instead of making it global
private static $id = 0;
// Use an instance variable to keep track of a particular instance's id
private $myId;
public function __construct() {
// Increment the static ID & assign it to the instance id.
$this->myId = self::$id++;
}
// Provide a public getter, so that the ID can't be changed
// externally to this class
public function getId() {
return $this->myId;
}
public abstract draw(); // Make sure all sub classes implement a draw() method.
}
class input extends fields {
// Don't need to call the parent constructor if you're not adding anything
// else. It will be called automatically.
public function draw() {
echo '<input>';
}
}
class textarea extends fields {
public function draw() {
echo '<textarea>';
}
}

Related

PHP: Variable declared in an abstract class does not change its value from the cild classes

I'm trying to increase the value of a variable which is declared in an abstract class, but every time I increase it from the child classes it keeps assigning 1 instead of increasing its value in every instance.
<?php
abstract class sum {
private $sumResult = 0;
}
class test1 extends sum {
private $sumResult;
public function __construct() {
$this->setSumResult();
}
public function setSumResult() {
$this->sumResult++; //here I try to increase the value of the variable
}
public function getSumResult() {
return $this->sumResult;
}
}
class test2 extends sum {
private $sumResult;
public function __construct() {
$this->setSumResult();
}
public function setSumResult() {
$this->sumResult++; //here I try to increase the value of the variable
}
public function getSumResult() {
return $this->sumResult;
}
}
$test1 = new test1();
$test2 = new test2();
echo $test2->getSumResult(); //Here it prints out 1 instead of 2.
?>
So, what I want is to increase the value of the variable sumResult in every instance, but it is not working. In the code I wrote it should return 2 instead of 1.
What am I doing wrong?
Thank you in advance
Classes provide a blueprint for the construction of instances. So, each instance has its own set of member variables. Changing a member variable in one instance doesn't change its value for another instance.
Since there's no rule without exception, there are static methods and members. These belong to the class, not the instance.
To share a variable across all instances of the classes, you will need to declare it as static and here I use protected to allow the derived classes to access the same value. Then each reference to this variable is done using self::$sumResult. You also don't need to declare the variable in each class as this can hide the field in the parent class.
abstract class sum {
protected static $sumResult = 0;
}
class test1 extends sum {
public function __construct() {
$this->setSumResult();
}
public function setSumResult() {
self::$sumResult++;
}
public function getSumResult() {
return self::$sumResult;
}
}
class test2 extends sum {
public function __construct() {
$this->setSumResult();
}
public function setSumResult() {
self::$sumResult++;
}
public function getSumResult() {
return self::$sumResult;
}
}
$test1 = new test1();
$test2 = new test2();
echo $test2->getSumResult(); //Here it prints out 2.
Just an alternative version to what others posted, if that can help. More logical this way imho, considering how static methods/properties work:
<?php
abstract class sum
{
private static $sumResult = 0;
public function __construct()
{
self::setSumResult();
}
public static function getSumResult()
{
return self::$sumResult;
}
private static function setSumResult()
{
self::$sumResult++;
}
}
class test1 extends sum {}
class test2 extends sum {}
$test1 = new test1();
$test2 = new test2();
echo sum::getSumResult();

Possible for instantiated sub class to access property set by parent class?

I'm new to object-oriented PHP, and still wrapping my head around classes and subclasses.
In this simple example, $this->siteName will be empty inside the instantiated class Two (called from class One's method "build").
Is there any way for an instance of class Two to inherit that property value set by the parent?
I know I could just turn class Two into a method of class One, but I like having separate files for organization.
Is there a better way to do this?
File One
class One {
protected $siteName;
function __construct() {
$this->siteName = 'Example';
}
public function build() {
$two = new Two();
return $two->build();
}
}
File Two
class Two extends One {
public function build() {
return "<h1>$this->siteName</h1>";
}
}
By the sound of it you're trying to solve the wrong problem.
My understanding of your question is that you basically want to have the code for public function build() in another file for organisation reasons.
Here's how:
class One {
private $siteName;
public function __construct() {
$this->siteName = 'Example';
}
use One_build;
}
Assuming you have the proper autoloading setup, or have included the files correctly, you can then have your separate file:
trait One_build {
public function build() {
return "<h1>".$this->siteName."</h1>";
}
}
This allows for a horizontal spreading of your source code.
Your code does work with a few tweaks. You need to concatenate your string's h1 tags with your variable, quotes can't be around the entire thing.
Other than that, just create an instance of the class and trying it out.
class One {
protected $siteName;
function __construct() {
$this->siteName = 'Example';
}
public function build() {
$two = new Two();
return $two->build();
}
}
class Two extends One {
public function build() {
return "<h1>".$this->siteName."</h1>";
}
}
$taco = new Two();
echo $taco->build();
This will return <h1>Example</h1>

Correct way of using polyporphism in php?

I'm new to object oriented php. And if there are no functions in the method testing() in the HumanClass, should i declare them as abstract?
<?php
class HumanClass
{
private $legs;
private $hands;
public function __construct($legs, $hands)
{
$this->legs = $legs;
$this->hands = $hands;
}
public function testing()
{
}
}
class StudentClass extends HumanClass
{
private $books;
public function __construct($legs, $hands, $books)
{
parent::__construct($legs, $hands);
$this->books = $books;
}
public function testing()
{
echo "StudentClass called.";
}
}
function callClass(HumanClass $c)
{
$c->testing();
}
$example = new StudentClass(4, 2, 1);
callClass($a);
?>
Is it possible to have something like this?
echo $a->testing();
instead of having another method to call testing().
Given the code that you give, it's far from clear what the testing() function is supposed to do other than just exist for you to try things. The answer to that will also determine whether the versions in the baseclass should remain there as empty function.
There are other options, too, e.g. that the derived class first invokes the baseclass (extending), or that the baseclass doesn't contain an abstract or concrete such function but only the derived one does. Which to choose is up to the informed programmer to decide.

Common parent classes

I have some variables and functions which need to be available for different classes. Hence, I put all definitions (Variables / functions) to some class:
class common_functions() {
function __construct() {
$this->define_variables();
$this->connect_to_database();
echo "EXEC";
}
function define_variables() {
$this->var1 = "foo";
$this->var2 = "bar";
}
function connect_to_database() {
mysql_connect(...)
}
function do_something() {
//...
}
}
which is the parent of all the others:
class orders extends common_functions {
private $order_item;
function __construct() {
parent::__construct()
$order_item = new item();
}
function show_something() {
echo $order_item->get_something()*$this->var1;
}
}
class item extends common_functions {
pivate $some_number;
function __construct() {
parent::__construct()
$this->number = 123;
}
function get_something() {
return $this->var2*$this->var1*$this->number;
}
}
class some_other_class extends common_functions {
function __construct() {
parent::__construct()
}
// ..
}
However, as executing
$o = new order();
$o->show_something();
the output is
EXEC
EXEC
since the common_functions class is called twice. Especially also mysql-connection is established several times which is quite unefficient.
What I need is some technique so that all the functions and variables (and database-connections) from common_functions are available to all classes without the drawback that e.g. connect_to_database() is executed several times. Some ideas?
If I were you I'd redesign my implementation. Why? Well because it seems to me that neither some_other_class nor item is a common_functions. However they both have common_functions. Thus I'd create only one instance of that class and pass it into the constructor.
Something like this:
class Item {
private $common_functions;
public function __construct($common_functions) {
$this->common_functions = $common_functions;
}
}
class Order {
private $common_functions;
public function __construct($common_functions) {
$this->common_functions = $common_functions;
}
}
What happens now is that both the item and some_other_class objects has a dependency which we inject to common_functions. This obviously means that you have to pass some values to the methods in common_functions but that is a very small price to pay considering what you gain from not inheriting common_functions, like only one db-connection.
Inheritance is cool but in practice it isn't used all that much. It's often much better compose objects than to inherit a bunch of stuff. When designing OO-classes always consider wether an objects relation is an is a or has a relation.
So what you could do using the above example of the orders constructor is the following:
class orders {
private $common_functions;
public function __construct($common_functions) {
$this->common_functions = $common_functions;
$order_item = new Item($common_functions);
}
}
That way both item and order will share the same common_functions object.
Assign a static null variable initially in parent class and check if its null or not.
class common_functions {
private static $dbInstance = null;
function __construct() {
if(self::$dbInstance == null) {
self::$dbInstance = $this->connect_to_database();
}
}
...
return the the database connection handler or any other than the null value in $this->connect_to_database();

PHP Classes: get access to the calling instance from the called method

sorry for that weird subject but I don't know how to express it in an other way.
I'm trying to access a method from a calling class. Like in this example:
class normalClass {
public function someMethod() {
[...]
//this method shall access the doSomething method from superClass
}
}
class superClass {
public function __construct() {
$inst = new normalClass;
$inst->someMethod();
}
public function doSomething() {
//this method shall be be accessed by domeMethod form normalClass
}
}
Both classes are not related by inheritance and I don't want to set the function to static.
Is there any way to achieve that?
Thanks for your help!
You can pass a reference to the first object like this:
class normalClass {
protected $superObject;
public function __construct(superClass $obj) {
$this->superObject = $obj;
}
public function someMethod() {
//this method shall access the doSomething method from superClass
$this->superObject->doSomething();
}
}
class superClass {
public function __construct() {
//provide normalClass with a reference to ourself
$inst = new normalClass($this);
$inst->someMethod();
}
public function doSomething() {
//this method shall be be accessed by domeMethod form normalClass
}
}
You could use debug_backtrace() for this. It is a bit iffy but for debugging purposes it is usefull.
class normalClass {
public function someMethod() {
$trace = debug_backtrace();
$trace[1]['object']->doSomething();
}
}
You have a few options. You can use aggregation like so
class normalClass
{
protected $superClass;
public function __construct( superClass $superClass )
{
$this->superClass = $superClass;
}
public function someMethod()
{
$this->superClass->doSomething();
}
}
class superClass
{
public function __construct()
{
$inst = new normalClass( $this );
$inst->someMethod();
}
public function doSomething()
{ //this method shall be be accessed by domeMethod form normalClass
}
}
Or just a straight-up setter
class normalClass
{
protected $superClass;
public function setSuperClass( superClass $superClass )
{
$this->superClass = $superClass;
}
public function someMethod()
{
if ( !isset( $this->superClass ) )
{
throw new Exception( 'you must set a superclass' );
}
$this->superClass->doSomething();
}
}
class superClass
{
public function __construct()
{
$inst = new normalClass();
$inst->setSuperClass( $this );
$inst->someMethod();
}
public function doSomething()
{ //this method shall be be accessed by domeMethod form normalClass
}
}
Depending on your use case, you might want to pass the instance to the function only:
class normalClass {
public function someMethod($object) {
$object->doSomething();
}
}
If normalClass::someMethod() can be called by multiple, distinct $objects, this might be the better choice (instead of providing the $object to the whole normalClass instance).
But regardless of that you might consider creating an Interface to use for type hinting:
interface ISomethingDoer {
public function doSomething();
}
class normalClass {
public function someMethod(ISomethingDoer $object) {
# Now PHP will generate an error if an $object is passed
# to this function which does not implement the above interface.
// ...
class superClass implements ISomethingDoer {
// ...
woah I had the same problem than you but instead of going with the so simple pass the reference to the object, I went with an event manager, Basically, when something would happen in the normal class, it would trigger an event which was listened by a class and that said class(the listener) would call the super class to execute that functionality and if necessary pass it new arguments.
Anyways, whether you pass it as a parameter to your object or you go with an event based approach, both solutions work. Choose the one you prefers.
For more information on events, sympony explains it quite good.
http://symfony.com/doc/current/components/event_dispatcher/introduction.html

Categories