Better to use an Object or a Static Function in PHP? - php

I am trying to learn OO and classes and all that good stuff in PHP, I am finally learning the sytax good enough to use it some and I am curious if there is any benefit of starting a new object instead of just using static methods...let me show some code for what I mean...
<?PHP
test class
{
public function cool()
{
retunr true;
}
}
//Then calling it like this
$test = new test();
$test->cool();
?>
OR
<?PHP
test class
{
public static function cool()
{
retunr true;
}
}
//Then calling it like this
test::cool();
?>
I realize this is the most basic example imaginable and the answer probably depends on the situation but maybe you can help me understand a little better

For your example, it is better to use a static function, but most situations will not be so simple. A good rule of thumb to start with is that if a method doesn't use the $this variable, then it should be made static.

Think of classes like 'blueprints' to an object. you want to use the static method when it is a general function that could apply to anywhere, and use methods when you want to reference that specific object.

Here is an article that discusses differences in performance between these concepts:
http://www.webhostingtalk.com/showthread.php?t=538076.
Basically there isn't any major difference in performance, so then the choice is made based on your design.
If you are going to create an object several times, then obviously a class makes sense.
If you are creating a utility function that isn't tied to a particular object, then create a static function.

Related

How to create an object using Factory method, instead of supplying alternative object constructor

I am having some trouble applying Factory Pattern.
I have a class that I usually call as Product($modelNumber, $wheelCount). But in a part of legacy code that I am refactoring, I do not have $modelNumber, and only have $productID, where the link between {$modelNumber, $productID} is in the database (or in my case I can hardcode it, as I only have a select few products at the moment).
I need to be able to create my class using $productId, but how?
Using Procedural ways I would have a function that does the lookup, and I would put that function in a file, and include that file anywhere where I need to do the lookup. Thus do this:
$modelNumber = modelLookup($productId)
Product($modelNumber, $wheelCount);
But how do I do it using Object Oriented way?
Note: I have posted a more detailed situation here: https://softwareengineering.stackexchange.com/q/233518/119333 and this is where Factory pattern (and other patterns, like interfaces and function pointer passing) were suggested conceptually, but I hit a wall when trying to implement them in PHP. It kind of seems like a simple question, but I think there are several ways to do it and I am a bit lost as to how. And so I need some help.
I provided a conceptual answer to your SRP problem on Programmers Exchange but I think I can demonstrate it here.
What you basically want is some other object that will do the work to get you the model number of given product ID.
class ProductModelNumberProvider {
public function findByProductId($productId) {
// The lookup logic...
}
}
Your factory should provide a setter constructor so it can make use of this object internally to lookup the model number if needed. So basically you will end up with a ProductFactory similar to this.
class ProductFactory {
private $productModelNumberProvider;
public function __construct(ProductModelNumberProvider $productModelNumberProvider) {
$this->productModelNumberProvider = $productModelNumberProvider;
}
public function getProductByIdAndWheels($productId, $wheels) {
$modelNumber = $this->productModelNumberProvider($productId);
return $this->getProductByModelNumberAndWheels($modelNumber, $wheels);
}
public function getProductByModelNumberAndWheels($modelNumber, $wheels) {
// Do your magic here...
return $product;
}
}
EDIT
On second thought the setter is not the best approach since having a ProductModelNumberProvider instance is mandatory. That is why I moved it to have it injected through the constructor instead.
I can think of something like this:
$factory = new ProductBuilder();
$factory->buildFromProductId($productId, $wheelCount); //uses modelLookup() internally
$factory->buildFromModelNumber($modelNumber, $wheelCount); //just returns Product()
It is basically creating a class on top of the procedural function, but it does separate the logic of creating the class separately from looking up the mapping.

Way to change results of object's methods

I was trying to find a way to execute some code to alter the results of an objects methods without actually touching the object's code. One way I came up is using a decorator:
class Decorator {
private $object;
public function __construct($object) {
if (!is_object($object)) {
throw new Exception("Not an object");
}
$this->object = $object;
}
protected function doSomething(&$val) {
$val .= "!!";
}
public function __call($name, $arguments) {
$retVal = call_user_func_array(array($this->object, $name), $arguments);
$this->doSomething($retVal);
return $retVal;
}
}
class Test extends BaseTest {
public function run() {
return "Test->run()";
}
}
$o = new Decorator(new Test());
$o->run();
That way it will work properly but it has one disadvantage which makes it unusable for me right now - it would require replacing all lines with new Test() with new Decorator(new Test()) and this is exactly what I would like to avoid - lots of meddling with the existing code. Maybe something I could do in the base class?
One does not simply overload stuff in PHP. So what you want cannot be done. But the fact that you are in trouble now is a big tell your design is flawed. Or if it is not your code design the code you have to work with (I feel your pain).
If you cannot do what you want to do it is because you have tightly coupled your code. I.e. you make use of the new keyword in classes instead of injecting them (dependency injection) into the classes / methods that need it.
Besides not being able to easily swap classes you would also have a gard time easily testing your units because of the tight coupling.
UPDATE
For completeness (for possible future readers): if the specific class would have been namespaced and you were allowed to change the namespace you could have thought about changing the namespace. However this is not really good practice, because it may screw with for example autoloaders. An example of this would be PSR-0. But considering you cannot do this either way I don't see it is possible what you want. P.S. you should not really use this "solution".
UPDATE2
It looks like there has been some overload extension at some time (way way way back), but the only thing I have found about it is some bug report. And don't count on it still working now either way. ;-) There simply is no real overloading in PHP.
Found something (a dead project which doesn't work anymore that enables class overloading): http://pecl.php.net/package/runkit
Possibly another project (also dead of course): http://pecl.php.net/package/apd
I am not a PHP programmer, but I think that AOP is what you are looking for. You can try some frameworks, for example listed in this answer.
From the Wikipedia article on the decorator pattern:
Subclass the original "Decorator" class into a "Component" class
So I think you're supposed to keep the class to be decorated private and expose only the already-decorated class.

When to use `public static function createInstance()` rather than a usual constructor to instanciate a class?

I'm studying this code:
http://www.w3style.co.uk/a-lightweight-and-flexible-front-controller-for-php-5
In it the author uses a static function to instantiate a class. I'm basically a beginner and I had never seen this. Why would one use a static instantiator rather than the usual constructor?
Here is the code:
index.php
<?php
define("PAGE_DIR", dirname(__FILE__) . "/pages");
require_once "FrontController.php";
FrontController::createInstance()->dispatch();
FrontController.php
<?php
class FrontController {
public static function createInstance() {
if (!defined("PAGE_DIR")) {
exit("Critical error: Cannot proceed without PAGE_DIR.");
}
$instance = new self();
return $instance;
}
public function dispatch() {....}
This is a workaround for PHP, since it is too dumb for stuff like this:
(new SomeClass())->doSomething();
Oneliners like that are impossible in native PHP. That is why some people wrap the instantiation of the class in a static method to make it possible:
SomeClass::create()->doSomething();
It helps to keep the scope clean, since you do not need extra variables. It would look like this, otherwise:
$instance = new SomeClass();
$instance->doSomething();
unset($instance);
EDIT: let me quote Gordon here (from the comments): "Static calls are the same as putting a function into the global scope. Calling it will always have a dependency on the global scope." You should be aware of this fact, as it makes your code less flexible.
The most common situations are where you want to create a singleton instance, or using a factory pattern.
PHP only allows one constructor, which means if you want to have more than one way to construct an object, mutliple static function are considered a valid solution. However, just having a static function that calls the constructor doesn't seem to make much sense.
For example, you could have a constructor that takes parameters for each property of the object. And a static function which takes just an id, and does a database call to retrieve all the properties to retrieve the object. This means you don't have to have all the database procedures in your calling code. The static function takes responsibility.
It is often suggested to make a seperate Factory class to do this, but I don't think that always makes sense. You should read in on the subject before making a decision if it makes sense for you.

Good Idea or Bad Idea? Using a Static Class Variable to Store a Global

I have a class that I am using all over the place in my code. It contains settings and other core functionality. Here's what I'm doing right now to use the class.
$settings = new Settings();
$settings->loadSettings();
Then, when I need to the code in some random function in another class, I do something like this:
function abc() {
global $settings;
$variable = $settings->a;
}
I'm sick and tired of randomly calling global $settings all over the place to pull in that settings object. I don't want to use the $_GLOBALS array (I don't know why, I just don't want to).
I'm thinking I want to switch to have a static class variable called $settings inside of settings. The code would look like this:
Settings::$settings = new Settings();
Settings::$settings->loadSettings();
Then, whenever I want to use it, I never have to worry about sucking it in via the global operator:
function abc() {
$variable = Settings::$settings->a;
}
Good idea or bad idea?
Well it's probably an improvement on globals, because it solves all the ugly scoping issues that globals cause. Getting rid of the global operator is generally a good thing! What you are doing is not dissimilar to the singleton pattern, though it's considerably simpler. (See the "Singleton" section at http://php.net/manual/en/language.oop5.patterns.php for more information on the pattern.) Your solution is almost certainly fine for your purposes.
On the other hand, there may be better ways of achieving the same thing that decouple your code more. That is to say, each class becomes more capable of being used in another project without significant recoding. One way to do this would be to "inject" the settings object into each class:
class ABC {
private $settings;
public function __construct($settings) {
$this->settings = $settings;
}
public function someMethod() {
$variable = $this->settings->a;
}
}
This would be more work, but may improve the re-usability of your code. You could then, for example, write a different settings class for every project but use the same ABC class.
This process, where you "inject" an object into another object that depends on it, is called dependency injection. There are other, more complex ways of doing this, including complex containers. See http://fabien.potencier.org/article/11/what-is-dependency-injection for an interesting set of tutorials on the subject. They're probably incidental to your current needs, but may help either now or in the future.
It seems you are looking for a Singleton. Basically the idea is to have a class which has a public static method getInstance() which returns an instance of the class itself. The first time you call the method, it stores the instance in a private property, and all later time it returns the stored instance. In this way, whenever you call Settings::getInstance(), you are guaranteed to have a copy of the same object. Then you can store settings in this object.

Call a protected method from outside a class in PHP

I have a very special case in which I need to call a protected method from outside a class. I am very conscious about what I do programmingwise, but I would not be entirely opposed to doing so in this one special case I have. In all other cases, I need to continue disallowing access to the internal method, and so I would like to keep the method protected.
What are some elegant ways to access a protected method outside of a class? So far, I've found this.
I suppose it may be possible create some kind of double-agent instance of the target class that would sneakily provide access to the internals...
In PHP you can do this using Reflections.
To invoke protected or private methods use the setAccessible() method
http://php.net/reflectionmethod.setaccessible (just set it to TRUE)
I would think that in this case, refactoring so you don't require this sort of thing is probably the most elegant way to go. In saying that one option is to use __call and within that parse debug_backtrace to see which class called the method. Then check a friends whitelst
class ProtectedClass {
// Friend list
private $friends = array('secret' => array('FriendClass'));
protected function secret($arg1, $arg2) {
// ...
}
public function __call($method, $args) {
$trace = debug_backtrace();
$class = $trace[1]['class'];
if(in_array($class, $this->friends[$method]))
return $this->$method($args[0], $args[1]);
throw new Exception();
}
}
I think I need a shower.
This is a little kludgy, but might be an option.
Add a child class for the sake of accessing your protected function
public class Child extends Parent {
public function protectedFunc() {
return parent::protectedFunc();
}
}
Then, instantiate an instance of Child instead of Parent where you need to call that function.
I'm just throwing this out there since I haven't programmed in PHP in two years. Could you just add a function to the class that calls the protected method like so?
$obj->publicFunc = create_function('$arg', 'return $this->protectedFunc($arg);');
Edit:
I think Tom's correct in looking at the documentation for create_function. It looks like the scope of $this will be "wrong" when you try to call it with this example.
It looks like traditional anonymous functions are supported since PHP 5.3.0 as well (and my first solution probably won't work), so I'd probably write it like this instead:
$obj->publicFunc = function($arg) {
return $this->protectedFunc($arg);
};
Since I think it looks a little cleaner (and your IDE of choice will highlight it better of course).
Ugh, I tried using Reflection to call the method but PHP won't allow you to do that either. It seems that you're going to have to use some sort of child class like the other posters have suggested. If you find a method that works, the developers will likely classify it as a bug in the future and break your code when you upgrade to the next version.
I recommend extending the class.
I'd think about what is the matter with the program design if I have to call a private function?
It used to be the case when
your class is responsible for several things (it is really two or thre calsses wrapped together) or
the rules of encapsulation are broken (utility functions, for example)
By finding any way to walk around this questions, you'll be nowhere nearer to the real solution.
Suppose your method declaration goes like so:
protected function getTheFoo() {
...
}
protected function setTheFoo($val) {
...
}
Usage:
$obj->__get('the_foo');
$obj->__set('the_foo', 'myBar');
This bypasses the protected methods and goes directly straight to the instance variables.

Categories