I'm sorry I could not come up with a more descriptive title. My problem is the following. Assume that you have two classes A and B and you know that sometimes it may happen that some code tries to instantiate an object of type A when what is actually needed is an object of type B. The point is that the code to decide which one is the right object naturally belongs to class A and not to the client code.
In javascript (ok, js doesn't have classes, but it makes the point clear) you can simply do
function A() {
if(some_condition) {
return new B();
}
//else we proceed to customize and return our object
}
I want to do something similar in PHP. The best thing I can come up with is
class A {
private function __construct() {
//whatever you need to do
}
public static function getInstance() {
if(some_condition) {
return new B();
}
else {
return new A();
}
}
}
The problem is that the client code will always have to know that A is special and you have to instantiate objects with a static method.
Is there a way to delegate to A the choice of the type of object to return in a seamless way?
Unfortunately no, the best i think you can do is something like:
class Decider {
public static function decide() {
if(some_condition) {
return "A";
}
else {
return "B";
}
}
}
$new_class = Decider::decide();
$new_object = $new_class();
But then again this is really no different then the way you approached it. I wouldnt consider this an invalid design patter though, however i would leave it to an external class to do the deciding rather then have class "A" or class "B" do the deciding within them. Ideally your classes should be encapsulated in such a way that they do not require other classes unless they are member variables of the class itself or passed into the class for functional purposes.
Related
Likely this has already been asked, but nevertheless, here goes. This may fall under best practice or security... I'm not really sure.
In my application, I am using a nested object, that is called in the __construct() function. Sort of like this:
class user {
public $userID = NULL;
public $someObject = NULL;
public function __construct() {
$this->userID = getThisUser();
$this->someObject = new objectBuilder($this->userID);
}
public function getThisUser() {
// ...
}
}
class objectBuilder {
public $buriedVar = NULL;
public function __construct($uid = NULL) {
if( !isset($uid) ) {
$this->buriedVar = setTheObject($uid);
} else {
$this->buriedVar = setTheObject(0);
}
}
public function setTheObject($id) {
// ...
return "random string";
}
}
$tom = new user();
Obviously terrible outline here, but the point is, I can then call $tom->someObject->buriedVar and it'll return "random string".
While looking for a way to nest classes, I noticed no one recommends this as a method for storing objects inside of another object. I'm curious of a few things:
1) Is this insecure?
2) Are the vars inside the nested object exclusive to the call made inside $tom->__construct(), or if I create another object using new objectBuilder() is it overwriting the one inside $tom->someObject? I haven't noticed this, but am not sure how to test for that entirely.
3) Is there something else I'm missing? A best practice reason not to instantiate an object inside a class? I've been using it for years and it works great for what I've done. Is it a speed thing?
1) Is this insecure?
Not inherently, no.
2) Are the vars inside the nested object exclusive to the call made
inside $tom->__construct(), or if I create another object using new
objectBuilder() is it overwriting the one inside $tom->someObject? I
haven't noticed this, but am not sure how to test for that entirely.
This is a fundamental question between class and object. Objects are instances of a class and there can be multiple. The only things that would be overwritten are static properties and methods. You could test it like this:
<?php
$obj1 = new objectBuilder();
$obj2 = new objectBuilder();
if ($obj1 !== $obj2) {
echo "objects are not the same\n";
}
if ($obj1->buriedVar !== $obj2->buriedVar) {
echo "nested objects are not the same either\n";
}
$obj3 = new objectBuilder(1);
if ($obj1->buriedVar != $obj3->buriedVar) {
echo "even the values of two different buried vars with different values are different.\n";
}
if ($obj1->buriedVar == $obj2->buriedVar) {
echo "counter-example: nested variables with the same values set are similar.\n";
}
It helps to know the difference between equality and identity (see this SO post).
3) Is there something else I'm missing? A best practice reason not to
instantiate an object inside a class? I've been using it for years and
it works great for what I've done. Is it a speed thing?
You touched on it briefly. What you should know is that this is not scalable and is difficult to test.
Imagine you're creating a website for dogs.
<?php
class Bio
{
public function __construct()
{
$this->dog = new Dog('Terrier');
}
}
class Dog
{
private $animal = 'dog';
private $noise = 'woof!';
private $breed;
public function __construct($breed=null)
{
$this->setBreed($breed);
}
public function setBreed($breed)
{
$this->breed = $breed;
}
}
What if you want to add a new breed? Well... That's easy enough:
class Bio
{
// ...
public function __construct($breed)
{
$this->dog = new Dog($breed);
}
// ...
}
Cool! You've solved everything.
Except...
One day you want to create a section for cats, because one of your best writers also loves cats, and you sense an untapped market.
Uh oh...
You can refactor the code, of course. But you wrote it a long time ago. Now you have to go in and figure out where everything went. No big deal.. A bit annoying but you fixed it!
But now you have another problem. Turns out that the same author wants to add different traits to the breed. You're surprised this hasn't come up sooner but, hey, it's probably a good thing to have.
Now you need to go in to the Dog object, and the Cat object, and add traits.
Every single time.
On. Every. Bio.
After some reconfiguring, you've created something monstrous like this:
$article1 = new Bio('Terrier', 'dog', ['independent']);
$article2 = new Bio('Persian', 'cat', ['flat-faced']);
//... and so on, and so on
The next time the author asks for something, you fire her and then tear your hair out in a mad rage.
Or, from the beginning, you use Dependency Injection.
<?php
class Bio
{
private $animal;
public function __construct(AnimalInterface $animal)
{
$this->animal = $animal;
}
}
interface Animal
{
public function getType();
public function setBreed($breed);
public function getBreed();
public function setTraits(array $traits);
public function getTraits();
}
abstract class AbstractAnimal implements AnimalInterface
{
private $breed;
private $traits = [];
abstract public function getType();
public function setBreed($breed)
{
$this->breed = $breed;
}
public function getBreed()
{
return $this->breed;
}
public function setTraits(array $traits)
{
$this->traits = $traits;
}
public function getTraits()
{
return (array)$this->traits;
}
}
class Cat extends AbstractAnimal
{
public function getType()
{
return 'cat';
}
}
class Dog extends AbstractAnimal
{
public function getType()
{
return 'dog';
}
}
This pattern requires little to no editing after it has been created.
Why? Because you are injecting the object to nest into the class, rather than instantiating it in the object.
$bio1 = new Bio($dog); $bio2 = new Bio($cat); can always stay like this. Now you just edit the $dog and $cat objects. The added benefit is that these objects can be used anywhere.
But what about utility classes?
(This is where testability comes in. If you haven't worked with unit testing, I recommend reading up on it in the link to PHPUnit below. I'm not going to dwell on how that works as it's off topic).
Dependency Injection is well and good if you have classes that require customization. But what about utility classes that just house various functions?
class Utils
{
public function add($a, $b)
{
return $a + $b;
}
}
You might think that you can call this function safely from the constructor. And you can. However, one day you might create a log method in your Utils class:
public function log($msg)
{
exec("cat '$msg' > /tmp/log.txt");
}
This works just fine. However, when you run tests, your /tmp/log.txt file complains. "Invalid permissions!". When this method is run via your website, log.txt needs to be writeable by www-data.
You could just chmod 777 /tmp/log.txt, but that would mean everyone who has access to your server can write to that log. Additionally, you may not want to always write to the same log when you're testing as when you're navigating through the web interface (Personally, I would find it confusing and cluttering).
PHPUnit and other unit testing services allow you to mock various objects. The problem is that you have classes calling Utils directly.
You have to find a way to manually override the constructor. Look at PHPUnit's manual to find out why this maybe isn't ideal.
So if you're not using Dependency Injection, what do you do?
PHPUnit suggests, amongst other fixes, moving this Utils object instantiation to another method and then stubbing/mocking that method in your unit test (I want to emphasize that this is after recommending Dependency Injection).
So the next best?
public function __construct()
{
$this->init();
}
private function init()
{
$this->utils = new Utils;
}
Now when you unit test, you can create a fake init method and it will be called as soon as the class is created.
In conclusion, the way you are currently instantiating classes is not scalable or easily testable in many real world situations. While it may be all right in limited situations, it is better to get used to the DI (Dependency Injection) pattern, because it will save you lots of headaches in the future.
I've learned that OOP is all about data encapsulation, but what about passing data between classes that have nothing to do with each other (would the below example be worthy of using extends)?
class Dog {
private $secretVar;
public function getSecretVar() {
$this->secretVar = 'psst... only for rainbow!';
return $this->secretVar;
}
}
class Rainbow {
public function __construct(Dog $Dog) {
print_r($Dog->getSecretVar());
}
}
$Dog = new Dog();
$Rainbow = new Rainbow($Dog);
// ... classes that don't need the $secretVar
How would you encapsulate $secretVar for only classes Dog and Rainbow? As of now, anyone can call getSecretVar(), and I'm having a hard time allowing that to happen as it seems to defeat the whole point of encapsulation.
Here's a solution, although, it's ugly.
class Dog {
private $secretVar = 'psst... only for rainbow!';
public function getSecretVar($caller == NULL) {
// Here's the trick...
if (get_class($caller) == 'Rainbow') {
return $this->secretVar;
} else {
return '';
}
}
}
class Rainbow {
public function __construct(Dog $Dog) {
print_r($Dog->getSecretVar($this));
}
}
$Dog = new Dog();
$Rainbow = new Rainbow($Dog);
// ... classes that don't need the $secretVar
It's ugly because it hard to maintain and not intuitive. If you really need to do this, there's most likely a flaw in your design.
It wouldn't make sense for a Dog to extend Rainbow or vice versa just to share a variable.
What you are asking of may be possible but I don't know. If it was C++ using the friend visibility, it is certainly possible.
In this case, you have to make it public or use a getter and setter.
Encapsulation is not ment to hide the value of the variable from the rest of the program but to have full control of how the rest of your program can access the variable.
By declaring the variable private you can check what values it can be set to and you can make changes to it before anybody reads it.
There is no real point in trying to let only some of the classes read the variable.
What you are trying to do could be achieved by using reflection to check which class and method calls the getSecretVar() method, but it's hardly ever useful.
In your case, you could use protected like this: (every class that extends hasSecret will have access to it.)
<?php
class HasSecret {
protected $secretVar = 'psst... only for rainbow!';
}
class Dog extends HasSecret {
public function getSecretVar() {
return $this->secretVar;
}
}
class Rainbow extends HasSecret {
public function __construct(Dog $Dog) {
print_r($Dog->getSecretVar());
}
}
$Dog = new Dog();
$Rainbow = new Rainbow($Dog);
Ok, i know that probably this is not possible, but i'll give it a try. Maybe my knowledge is not so good. Please don't downvote, this is just for curiosity and this maybe due to a poor OO design.
Assume that class definition for A is:
class A
{
public function build()
{
$data = $this->fetchData();
...
}
public function fetchData()
{
// Database eavy query
return $this->repository->fetchDataForCharting();
}
}
And then, without using a good and decent OO design, you create class B which is going to use fetchDataForCharting from the repository, for doing some other different calculations:
class B
{
public $data;
public function getMonthlyLimit()
{
// Database eavy query
$data = $this->getData();
}
public function getData()
{
return isset($this->data) ? $this->data :
$this->repository->fetchDataForCharting();
}
}
Sometimes you need only A, sometimes you need only B, sometimes both. Is there any way of overriding fetchData at runtime? I mean someting like $.extend() in jQuery:
$b = new B();
$b->getMonthlyLimit(); // $b->data filled
$a = new A();
// Override fetchData
$a = extend($a, 'fetchData', function() use($b) { return $b->data; });
$a->build(); // Just 1 query
There is no proper way to modify/replace/add a class method.
The runkit extension has runkit_method_redefine() and runkit_method_add() but both are experimental and ugly (they take a code string, not a Closure object like your anonymous function is).
It is not really clear to me what you are trying to do, but in PHP you can have calss B extend class A by writing the class B declaration as so:
Class B extends Class A {
...
}
You can the override the fetchData function within Class B like
public function fetchData {
// do something different than in class A
}
Or
public function fetchData {
// execute the Class A functionality first
parent::fetchData();
// now do something in addition to what is in Class A functionality
}
Hope this helps.
The short answer is no.
The closest you can get to exactly what you are asking is something like:
class A
{
public function __construct()
{
$this->bar = function()
{
};
}
public function foo()
{
$bar = $this->bar;
$bar();
}
}
$a = new A();
$a->bar = function()
{
// override
};
$a->foo();
Requires PHP 5.4 for $this support. But keep in mind that people do that sort of thing in JavaScript because it doesn't have "real" object oriented programming. You shouldn't try to emulate JavaScript, Ruby, Python, etc, just for the sake of doing it.
To be clear: in PHP, inheritance or composition or dependency injection is probably the proper way to go about what you are trying to do. (The above hack is definitely not what you should be doing.)
Here's the objective. I have a PHP class and there are one or two of its methods that I would like to override with my own. As I understand OOP (in PHP and in general) I could write a child class that extends it and overrides the functionality of the methods in question.
However, I was wondering if this is the best way of achieving this task and if this is a proper use for child classes or if there is something better in PHP for what I'm trying to do.
Yes, that is the best way to do it. The idea of extending a class is to provide extra or more specific functionality.
yes. this exactly what you use inheritance for.
A good principle though, is make sure your new inheriting class "is-a" base class.
Like Human is-a Mammal. Don't do Alien extends Human just because Alien does a lot of stuff Humans do.
So, are you asking if overriding methods (which requires extending the superclass) is the best way to override methods? Yes.
That is the most important use of subclasses. In fact, polymorphism is at the heart of OOP. The other use is to provide new properties/methods, but that usually won't be enough.
class oldClass {
public function methodToOverride() {
echo 'oh hai';
}
}
class childClass extends oldClass {
public function methodToOverride($arg, $arg2) {
// your custom code
echo 'hai world ' . $arg . ' ' . $arg2;
// if you need to still call the parent class
parent::methodToOverride();
}
}
$child = new childClass();
$child->methodToOverride('nom', 'nom');
Sounds like you're on the right track.
For the methods you want to override, you'd probably want to:
make sure you're not changing the intent of the method
know whether you have to call the base class's method within, and when
The only other way, would be to create a generic "superclass"...
class SuperClass {
protected $obj = null;
protected $overrides = array();
public function __construct($obj) {
if (!is_object($obj)) {
throw new InvalidArgumentException('Argument is not an object');
}
$this->obj = $obj;
}
public function __call($method, $args) {
$method = strtolower($method);
if (isset($this->overrides[$method])) {
array_unshift($args, $this);
return call_user_func_array($this->overrides[$method], $args);
} elseif (is_callable(array($this->obj, $method))) {
return call_user_func_array(array($this->obj, $method), $args);
} else {
throw new BadMethodCallException('Invalid Method Called');
}
}
public function __get($var) {
return isset($this->obj->$var) ? $this->obj->$var : null;
}
public function __set($var, $value) {
$this->obj->$var = $value;
}
public function addOverride($method, $callback) {
$this->overrides[strtolower($method)] = $callback;
}
}
It's not always the best solution, but it's possible that some situations exist to use something like that. It will let you "add" and "override" methods to any object at run time.
The better generic solution is to simply extend the class in a child class... But the above "superclass" does have some uses...
Another route I haven't seen mentioned here is to question whether it wouldn't be better to extract an abstract class and have the two classes extend that. Of course you would need to be able to alter the code of the first class for that (e.i. if the class came from an open source library you might refrain from changing the code).
you are on the right track
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.