I'm trying to work out how to best complete my design work on my classes.
my situation.
i have an order abstract class that contains order methods and information that are required for 2 children classes
order_Outbound
and order_inbound
each child class requires 2 static public method called create and get
but from what i have read about php 5.3 you cant have abstract static methods ???
so my thought was to have an interface Order_Interface which takes over that role but how do i implement it. do i still implement it in the parent class
in which case the parent abstract class still requires me to create a get and create method within the abstract class. or do i implement it in the children and extend from the abstract class???
ALSO!!!
both the outbound and inbound children require a create static method but require different parameters to be passed
can i in the interface have public static function create()
and in its implementation within order_outbound declare it public static function create($address, $reference, $orderID)
In most languages, including PHP, you cannot require a class to implement static methods.
This means neither class inheritance, nor interfaces, will allow you to require all implementors define a static method. This is probably because these features are designed to support polymorphism rather than type definition. In the case of static methods you'll never have an object to resolve the type from, so would have to do ClassName::Method explicitly, so the theory is you wouldn't gain anything from polymorphism.
As such, I see three solutions
Declaring the static methods in each class (after all, you are never going to
If you want a method to create instances of your class, but don't want to require an instance to call this method, you could create "Builder" classes to serve this purpose (e.g. OrderBuilder), such that you instantiate an OrderBuilder and call the Create method on this object instead to get Order instances.
(Recommended) Why aren't you simply using the Order constructor?
Update
After the comment from #hvertous, I decided to test this out. Using 3v4l we can see that abstract public static method:
Works for versions 5 > 5.1.6
Doesn't work for 5.2 > 5.6.38
Works for 7.0.0 > 7.3.1
Which confirms that it was removed in PHP 5.2, but if you are using PHP 7+ you can once again use abstract static methods.
Original answer
Yes, abstract static methods were removed in PHP 5.2. Apparently they were an oversight. See Why does PHP 5.2+ disallow abstract static class methods?.
However, you can have static methods in an interface, see this comment on php.net.
The problem you face is that you want your implementations to have different function signatures, which means that you probably shouldn't be using inheritance to solve your problem.
PHP 7.4+ allows to require a static method in an interface:
interface StaticInterface {
public static function interfaceMethod();
}
class MyProvider implements StaticInterface {
//public static function interfaceMethod() {}
}
Fatal error without the method: https://3v4l.org/YbA4u
No errors when implementing the method: https://3v4l.org/QNRJB
Related
I have a class that is containing 10 methods. I always need to use one of those methods. Now I want to know, which approach is better?
class cls{
public function func1(){}
public function func2(){}
.
.
public function func10(){}
}
$obj = new cls;
$data = $obj->func3(); // it is random, it can be anything (func1, or func9 or ...)
OR
class cls{
public static function func1(){}
public static function func2(){}
.
.
public static function func10(){}
}
cls::func3(); // it is random, it can be anything (func1, or func9 or ...)
It is an interesting subject. I'm gonna give you a design oriented answer.
In my opinion, you should never use a static class/function in a good OOP architecture.
When you use static, this is to call a function without an instance of the class. The main reason is often to represent a service class which should not be instantiated many times.
I will give you 3 solutions (from the worst to the best) to achieve that:
Static
A static class (with only static functions) prevent you from using many OOP features like inheritance, interface implementation. If you really think of what is a static function, it is a function namespaced by the name of its class. You already have namespaces in PHP, so why add another layer?
Another big disadvantage is that you cannot define clear dependencies with your static class and the classes using it which is a bad thing for maintenability and scalability of your application.
Singleton
A singleton is a way to force a class to have only one instance:
<?php
class Singleton {
// Unique instance.
private static $instance = null;
// Private constructor prevent you from instancing the class with "new".
private function __construct() {
}
// Method to get the unique instance.
public static function getInstance() {
// Create the instance if it does not exist.
if (!isset(self::$instance)) {
self::$instance = new Singleton();
}
// Return the unique instance.
return self::$instance;
}
}
It is a better way because you can use inheritance, interfaces and your method will be called on an instanciated object. This means you can define contracts and use low coupling with the classes using it. However some people consider the singleton as an anti pattern especially because if you want to have 2 or more instances of your class with different input properties (like the classic example of the connection to 2 different databases) you cannot without a big refactoring of all your code using the singleton.
Service
A service is an instance of a standard class. It is a way to rationalize your code. This kind of architecture is called SOA (service oriented architecture). I give you an example:
If you want to add a method to sell a product in a store to a consumer and you have classes Product, Store and Consumer. Where should you instantiate this method? I can guarantee that if you think it is more logical in one of these three class today it could be anything else tomorrow. This leads to lots of duplications and a difficulty to find where is the code you are looking for. Instead, you can use a service class like a SaleHandler for example which will know how to manipulate your data classes.
It is a good idea to use a framework helping you to inject them into each others (dependency injection) in order to use them at their full potential. In the PHP community, you have a nice example of implementation of this in Symfony for instance.
To sum up:
If you do not have a framework, singletons are certainly an option even if I personally prefer a simple file where I make manual dependency injection.
If you have a framework, use its dependency injection feature to do that kind of thing.
You should not use static method (in OOP). If you need a static method in one of your class, this means you can create a new singleton/service containing this method and inject it to the instance of classes needing it.
The answer depends on what those methods do. If you're using them to mutate the state of the object at hand, you need to use the instance method calls. If they're independent functionality, then you can use the static versions, but then I'd question why they're part of a class at all.
So, there is a very basic difference in static methods.
To use static functions, you don't need to initialise the class as an object. For example, Math.pow(), here .pow() (in Java; but the explanation still holds) is a static method.
The general rule is to make the helper methods static.
So, for example, if you have a Math class, you wouldn't want to fill the garbage collector with classes which just help other, more important, classes.
You can use it as dynamic initializers, if you please!
Let's say you have a class RSAEncryptionHelper, now you can generally initialize it without any parameters and this will generate an object with a key size of (say) 512 bits; but you also have an overloaded object constructor which gets all of the properties from other classes:
$a = new RSAEncryptionHelper::fromPrimeSet(...);
Within a PHP class you can use class/methods/attributes: Abstract, Static, Private, Public, etc ...
The best way is to know how to mix them all within a class depending on the need, I will give you a basic example:
Within the Person class, you have private and public methods, but you have a method called "get_nationality" so this is a function that you need somewhere else but you do not have the Person class installed yet, so this method you put it as STATIC in this way you can invoke the "get_nationality" method without installing any Person class, this makes your business model more optimal and in turn now resources in the CPU.
Static functions are also very useful but
I usually make traits when I have to create functions that are independently related to a class.
I don't know if this approach is better or not but most times I found it useful.
Just sharing my approach here so that I can learn more about its pros and cons.
You can think a factory. You will give some materials, it will give you same output. Then you should use static function.
class ProductDetails
{
public static function getRow($id, PDO $pdo): SingleProduct
{
// this function will return an Object.
}
}
I am not defining the Object here. Just where you need a Single Product you can simply do that ProductDetails::getRow(10, $pdo);
when I look through GitHub most projects define methods in the interface this way:
interface ExampleInterface
{
function getId();
}
my question now is why it is bad style to define the method visability in the Interface:
interface ExampleInterface
{
public function getId();
}
It makes the interface more strict but isn't that whats an interface used for?
what is the point of a private function in an interface? declaring public is redundant.
from TFM:
All methods declared in an interface must be public, this is the nature of an interface.
http://php.net/manual/en/language.oop5.interfaces.php
It is because an interface is a promise you give to the outside world of certain functionality. In your above example, whenever a class implements an interface, it is guaranteeing that the class will provide a method called getId to the outside world, irrespective of how it is implemented.
Hence, if you make a private promise, it is irrelevant as no one cares if there is a private method with some functionality, it is anyways not accessible by anyone else.
On the other hand, all methods in an interface are essentially public (since they are nothing but promises to the outside world) and hence you explicitly mentioning it as public is redundant.
Interfaces can only contain public methods, so the public is a bit redundant.
An interface can only have public members so there's no need to declare it. And these functions are meant to be inherited. Therefore; All methods declared in an interface must be public, that is its nature..
I can understand that private cannot work but protected as well?
I understand it is a "promise" to the outside world but if something implements an interface that method will stay protected therefore the same "promise" was still kept. It stated that there is function a, function b and also protected function c so from that we derive if I am not extending/implementing this then I can not have access to function c. Because it works the same when you read classes.
#AlphaMale Ok so what is the point of an interface then? It is used to create a "recipe" for a class right? So when you use it practically in code it will only be to implement and force methods. This becomes handy if methods are needed for your code to work and you don't want to force it to a specific class.
Lets say I have a to create Mailers, but I have to major processes where mails are needed but mailers will use different ways of constructing these mails. Now There needs to be a base send function that takes a message(any type) and a email address, but since the classes are in an open environment then it will be dangerous to leave this send function public and therefore we need it as a protected method. Now in the two Processes there are multiple mailers but each process shares the same way of constructing the method, so there is 2 abstract classes but now due to limited interfaces you now have to declare a third abstract class to contain this protected send function so that it can be extended as well otherwise you will have the same protected send function. If a new developer works on a completely new process and looks at the interface then the send function will never be forced. If we say it was possible to declare protected in an interface then outside if you check if something is an interface it will work the same as a class, you still can't access the the protected functions.
Private makes sense because then only the interface will know about these values and since an interface can't do anything this will be pointless.
I am using php 5.3, and yes, there is a bug open for that, but some think this is not a bug, and this makes me wonder.
abstract class A{
private function bobo(array $in){
//do something
}
}
class B extends A{
private function bobo($shmoo,$shmaa){
//do something
}
}
This throws an error. Shouldn't inheritance ignore private methods?!
'Declaration of B::bobo() should be
compatible with that of A::bobo()'
Note that the bug report is slightly off, as PHP will log this message any time you have an error level of E_STRICT (or, more recently, regardless of your error level provided that you've set a custom error handler).
PHP's visibility rules clearly demonstrate that a child lacks the ability to see its parent's private members, which I doubt is all that surprising to anyone. If the child can't see its parent's methods, I don't understand how it can have a duty to obey their definitions.
I personally think that the bug being marked as bogus without any explanation of why it wasn't a real flaw (since it's non-obvious and I couldn't find any mention of it in the documentation) is a bit wrong, but yeah. That aside, I'm of the opinion line 2669 in zend_compile.c should actually read as follows:
} else if (child->prototype &&
(EG(error_reporting) & E_STRICT || EG(user_error_handler))) {
...which would avoid the error popping up when the parent's method was marked private. Given that you always have the option not logging E_STRICT though, and it doesn't really negatively impact anything, I suppose it's not really a big deal. I definitely don't see how it could have been intentional, but I'm not a PHP engine developer either.
I think there are two possibilities here. Either it's a bug or the documentation on PHP.net/manual is incorrect. Here are three sections of the PHP manual. First on inheritance:
Object Inheritance
Inheritance is a well-established
programming principle, and PHP makes
use of this principle in its object
model. This principle will affect the
way many classes and objects relate to
one another.
For example, when you extend a class,
the subclass inherits all of the
public and protected methods from the
parent class. Unless a class overrides
those methods, they will retain their
original functionality.
This is useful for defining and
abstracting functionality, and permits
the implementation of additional
functionality in similar objects
without the need to reimplement all of
the shared functionality.
And on abstract classes:
Class Abstraction
PHP 5 introduces abstract classes and methods. It is not allowed to create an instance
of a class that has been defined as abstract. Any class that contains at least one
abstract method must also be abstract. Methods defined as abstract simply declare the
method's signature they cannot define the implementation.
When inheriting from an abstract class, all methods marked abstract in the parent's
class declaration must be defined by the child; additionally, these methods must be
defined with the same (or a less restricted) visibility. For example, if the abstract
method is defined as protected, the function implementation must be defined as either
protected or public, but not private.
Finally, interfaces
Object Interfaces
Object interfaces allow you to create code which specifies which methods a class must
implement, without having to define how these methods are handled.
Interfaces are defined using the interface keyword, in the same way as a standard class,
but without any of the methods having their contents defined.
All methods declared in an interface must be public, this is the nature of an interface.
Suffice it to say: there is nothing in the documentation that mentions inheritance of private methods. If there is a relationship between the parent and child method signatures, then it is not documented and the bug report should at least show someone that the documentation needs to be updated (if the decision to have this behavior is intentional). And if there was not supposed to be a relationship, then well, it's a real bug.
That's my opinion...
In the bug report when you remove the interface there isn't an error.
That makes it "more" strange behavior because the interface is just empty.
I guess this is a design decision of the language. The Java language developers decided that this should be possible.
Private methods should certainly not be ignored by inheritance, consider for example Template method pattern where you may override behavior of a function in a derived class, but the parent class can still call that function
public class Parent {
public final function doThings() {
$this->initialize();
$this->customStuff();
$this->cleanup();
}
private final function initialize() {
// initialize processing
}
private final function cleanup() {
// cleanup processing
}
private function customStuff() {
// parent specific processing
}
}
public class Derived extends Parent {
private function customStuff() {
parent::customStuff();
// + derived class specific processing
}
}
Calling doThings method on Derived class instance will do parent specific processing, but because of possibility to override private methods it is still possible to take advantage of the extension point provided by the non-final parent class customStuff method.
EDIT: Also PHP method signature consists of only the method name as you can define a method taking zero parameters and still call it with multiple parameters. Function can then access the arguments using func_get_args function.
I am working on a simple abstract database class. In my usage of this class, I'll want to have some instance be a singleton. I was thinking of having a abstract class that is not a singleton, and then extend it into another abstract class that is a singleton. Is this possible? Recommended?
Edit: I want to have two abstract that are practically identical, except one is a singleton. So the only difference will be that one will have all the functions of the other, but will have the other properties and methods that make it behave like a singleton.
I'd like to have one base class code base for this so as I make changes, I don't have to keep two files in sync.
In the way that I do things, I believe that there's no use for an abstract singleton. This is because,
1) What you want to be a singleton is the final class you instantiate for use within the application whether it'd be a library, model, controller or view and NOT the abstract.
2) Adding the singleton method is easy and can be written in 8 lines. See below.
protected static $_instance;
public static function getInstance()
{
if (!isset(self::$_instance)) {
self::$_instance = new self();
}
self::$_instance;
}
3) PHP 5.3 below version doesn't support late static binding. This will result in instantiating the abstract class instead of the final class inheriting it and will not function as expected, as already mentioned by Gordon and nuqqsa. So, for backward compatibility, better avoid it.
The implementation of the singleton pattern must satisfy two requirements:
It must provide a mechanism to access the singleton class instance without creating a class object
It must persist the singleton object so that it is not instantiated more than once
As long as that's provided, the variations are multiple. There's nothing wrong with making the class abstract extending from another abstract, if that's what you need. BUT, as #Gordon says, be aware that overriding static methods/properties causes peculiar behaviours in PHP < 5.3.
After enabling strict warnings in PHP 5.2, I saw a load of strict standards warnings from a project that was originally written without strict warnings:
Strict Standards: Static function Program::getSelectSQL() should not be abstract in Program.class.inc
The function in question belongs to an abstract parent class Program and is declared abstract static because it should be implemented in its child classes, such as TVProgram.
I did find references to this change here:
Dropped abstract static class functions. Due to an oversight, PHP 5.0.x and 5.1.x allowed abstract static functions in classes. As of PHP 5.2.x, only interfaces can have them.
My question is: can someone explain in a clear way why there shouldn't be an abstract static function in PHP?
It's a long, sad story.
When PHP 5.2 first introduced this warning, late static bindings weren't yet in the language. In case you're not familiar with late static bindings, note that code like this doesn't work the way you might expect:
<?php
abstract class ParentClass {
static function foo() {
echo "I'm gonna do bar()";
self::bar();
}
abstract static function bar();
}
class ChildClass extends ParentClass {
static function bar() {
echo "Hello, World!";
}
}
ChildClass::foo();
Leaving aside the strict mode warning, the code above doesn't work. The self::bar() call in foo() explicitly refers to the bar() method of ParentClass, even when foo() is called as a method of ChildClass. If you try to run this code with strict mode off, you'll see "PHP Fatal error: Cannot call abstract method ParentClass::bar()".
Given this, abstract static methods in PHP 5.2 were useless. The entire point of using an abstract method is that you can write code that calls the method without knowing what implementation it's going to be calling - and then provide different implementations on different child classes. But since PHP 5.2 offers no clean way to write a method of a parent class that calls a static method of the child class on which it is called, this usage of abstract static methods isn't possible. Hence any usage of abstract static in PHP 5.2 is bad code, probably inspired by a misunderstanding of how the self keyword works. It was entirely reasonable to throw a warning over this.
But then PHP 5.3 came along added in the ability to refer to the class on which a method was called via the static keyword (unlike the self keyword, which always refers to the class in which the method was defined). If you change self::bar() to static::bar() in my example above, it works fine in PHP 5.3 and above. You can read more about self vs static at New self vs. new static.
With the static keyword added, the clear argument for having abstract static throw a warning was gone. Late static bindings' main purpose was to allow methods defined in a parent class to call static methods that would be defined in child classes; allowing abstract static methods seems reasonable and consistent given the existence late static bindings.
You could still, I guess, make a case for keeping the warning. For instance, you could argue that since PHP lets you call static methods of abstract classes, in my example above (even after fixing it by replacing self with static) you're exposing a public method ParentClass::foo() which is broken and that you don't really want to expose. Using a non-static class - that is, making all the methods instance methods and making the children of ParentClass all be singletons or something - would solve this problem, since ParentClass, being abstract, can't be instantiated and so its instance methods can't be called. I think this argument is weak (because I think exposing ParentClass::foo() isn't a big deal and using singletons instead of static classes is often needlessly verbose and ugly), but you might reasonably disagree - it's a somewhat subjective call.
So based upon this argument, the PHP devs kept the warning in the language, right?
Uh, not exactly.
PHP bug report 53081, linked above, called for the warning to be dropped since the addition of the static::foo() construct had made abstract static methods reasonable and useful. Rasmus Lerdorf (creator of PHP) starts off by labelling the request as bogus and goes through a long chain of bad reasoning to try to justify the warning. Then, finally, this exchange takes place:
Giorgio
i know, but:
abstract class cA
{
//static function A(){self::B();} error, undefined method
static function A(){static::B();} // good
abstract static function B();
}
class cB extends cA
{
static function B(){echo "ok";}
}
cB::A();
Rasmus
Right, that is exactly how it should work.
Giorgio
but it is not allowed :(
Rasmus
What's not allowed?
abstract class cA {
static function A(){static::B();}
abstract static function B();
}
class cB extends cA {
static function B(){echo "ok";}
}
cB::A();
This works fine. You obviously can't call self::B(), but static::B()
is fine.
The claim by Rasmus that the code in his example "works fine" is false; as you know, it throws a strict mode warning. I guess he was testing without strict mode turned on. Regardless, a confused Rasmus left the request erroneously closed as "bogus".
And that's why the warning is still in the language. This may not be an entirely satisfying explanation - you probably came here hoping there was a rational justification of the warning. Unfortunately, in the real world, sometimes choices are born from mundane mistakes and bad reasoning rather than from rational decision-making. This is simply one of those times.
Luckily, the estimable Nikita Popov has removed the warning from the language in PHP 7 as part of PHP RFC: Reclassify E_STRICT notices. Ultimately, sanity has prevailed, and once PHP 7 is released we can all happily use abstract static without receiving this silly warning.
static methods belong to the class that declared them. When extending the class, you may create a static method of the same name, but you are not in fact implementing a static abstract method.
Same goes for extending any class with static methods. If you extend that class and create a static method of the same signature, you are not actually overriding the superclass's static method
EDIT (Sept. 16th, 2009)
Update on this. Running PHP 5.3, I see abstract static is back, for good or ill. (see http://php.net/lsb for more info)
CORRECTION (by philfreo)
abstract static is still not allowed in PHP 5.3, LSB is related but different.
There is a very simple work around for this issue, which actually makes sense from a design point of view. As Jonathan wrote:
Same goes for extending any class with static methods. If you extend that class and create a static method of the same signature, you are not actually overriding the superclass's static method
So, as a work around you could do this:
<?php
abstract class MyFoo implements iMyFoo {
public static final function factory($type, $someData) {
// don't forget checking and do whatever else you would
// like to do inside a factory method
$class = get_called_class()."_".$type;
$inst = $class::getInstance($someData);
return $inst;
}
}
interface iMyFoo {
static function factory($type, $someData);
static function getInstance();
function getSomeData();
}
?>
And now you enforce that any class subclassing MyFoo implements a getInstance static method, and a public getSomeData method. And if you don't subclass MyFoo, you can still implement iMyFoo to create a class with similar functionality.
I know this is old but....
Why not just throw an exception the that parent class's static method, that way if you don't override it the exception is caused.
I would argue that an abstract class/interface could be seen as a contract between programmers. It deals more with how things should look/ behave like and not implement actual functionality. As seen in php5.0 and 5.1.x it's not a natural law that prevents the php developers from doing it, but the urge to go along with other OO design patterns in other languages. Basically these ideas try to prevent unexpected behavior, if one is already familiar with other languages.
I don't see any reason to forbid static abstract functions. The best argument that there is no reason to forbid them is, that they are allowed in Java.
The questions are:
- Are the technically feasable? - Yes, since the existed in PHP 5.2 and they exist in Java.
So whe CAN do it. SHOULD we do it?
- Do they make sense? Yes. It makes sense to implement an part of a class and leave another part of a class to the user. It makes sense in non-static functions, why shouldn't it make sense for static functions? One use of static functions are classes where there must not be more than one instance (singletons). For example an encryption engine. It does not need to exist in several instances and there are reasons to prevent this - for example, you have to protect only one part of the memory against intruders. So it makes perfect sense to implement one part of the engine and leave the encryption algorithm to the user.
This is only one example. If you are accustomed to use static functions you'll find lots more.
In php 5.4+ use trait:
trait StaticExample {
public static function instance () {
return new self;
}
}
and in your class put at the beggining:
use StaticExample;
Look into PHP's 'Late Static Binding' issues. If you're putting static methods on abstract classes, you're probably going to run into it sooner rather than later. It makes sense that the strict warnings are telling you to avoid using broken language features.