I'm just getting into using classes in php and am coming from a C++ background. Literally every example I've seen shows methods being defined inside of the class definition, and I'm wondering if I can define my class methods outside of the class definition in order to improve readability?
Sort of. PHP 5.4 itroduced traits which is about as close as you're gonna get.
Yes you can in PHP. The function body for class methods can be put fully into external files:
class foo
{
function bar() {
include('import_method_body.php');
}
}
This works since ages.
In short, NO you can't do that;
In php every mothod should be inside the class. And that is why php isn't considered to be fully OOP language by some developers i have seen.
Related
Simple question, is it possible to dynamically add traits to a php class in runtime without using eval?
As Glavic said, you can't without using eval() or reflection hacks (and I'm not even sure about that).
But it's very unlikely you really need to.
You can achieve a lot with dynamic class composition (composing a class with some functionality you want into another class). That's simply a matter of putting a reference to the class with the desired functionality into a variable in the hosting class.
class SomeClassWithNeededFunctionality {}
class SomeClassThatNeedsTheFunctionalityOfTheOtherClass {
private $serviceClass = NULL;
public function __construct (SomeClassWithNeededFunctionality $serviceClass) {
$this -> serviceClass = $serviceClass;
}
}
No.
p.s. you can have them in standalone files, and use include() ?
I am looking to tidy up some code I have inherited. Essentially we have two classes (A + B) that extend off two separate classes that do various things differently, however A and B also share some functions. At present the functions are copy and pasted between the two and obviously I know this is wrong. I am looking to see if there it a solution to this so that I only have to define the functions once so that both A and B can use these. Any help would be great!
From php 5.4 you could use Traits.
Here is example from manual
<?php
trait ezcReflectionReturnInfo {
function getReturnType() { /*1*/ }
function getReturnDescription() { /*2*/ }
}
class ezcReflectionMethod extends ReflectionMethod {
use ezcReflectionReturnInfo;
/* ... */
}
class ezcReflectionFunction extends ReflectionFunction {
use ezcReflectionReturnInfo;
/* ... */
}
?>
In an ideal world, it's possible that what you really want there is multiple inheritance, but that is not supported by PHP (or many other languages) as it is much more complex than single inheritance.
One alternative to consider is arranging your code so that both classes eventually inherit from some common ancestor, so that you can put your code here. This may not always be desirable or practical, however, particularly if some of the classes extended are from different libraries with no shared dependency.
You might be able to alter the ancestry of some of your classes by using "composition" and "delegation" rather than direct inheritance. The basic idea is that rather than class B extending class A, you store an instance of class A as a property of class B; when certain methods of class B are called, they call corresponding methods of the A instance, while other methods of B are completely separate, and can be inherited from somewhere else. The magic method __call can be useful for implementing this without having to know every possible delegated method in advance.
As of PHP 5.4, there is a form of "horizontal code reuse" called Traits. Traits are sometimes described as "compiler-assisted copy-and-paste", because they don't represent any OOP relationship between the classes where they are used, only a way of editing the functions in one place.
If the functions are public, you might want to declare the classes as implementing an Interface, which lets other code check that a set of methods are available, usually by using the instanceof operator. This can be used in combination with a Trait, which contains the details of how those methods are implemented.
This is for fun only, don't scream please.
I would like to rewrite the content of a class's methods at runtime (I mean, without modifying the file, only replacing/editing the code in memory), is that possible?
Using reflection, or anything else?
Don't close this question please, I'm looking for another answer than runkit.
Why not simply create a new class that inherits from the one you want to modify and overwrite it's methods?
<?php
class MySimpleXML extends SimpleXMLElement {
public function themethodiwanttooverwrite() {
//...
}
}
?>
As long as the method isn't marked as final...
I'm from a Java background, and I want to use an inner class in php. Every time I put the inner class though, I get a syntax error. Is this possible with PHP? Also, how do I reference the outer class? Do I get access to ALL its data members?
<?php
class OuterClass {
var $x = 15;
function __construct() {
}
class InnerClass { // error when InnerClass is static
function __construct() { // error when InnerClass is static
echo $x;
}
}
}
?>
This is used for a MoveClass (as in make a move) of a specific card game. I think it'd be good design to put these classes together because they don't make sense apart. Also, the MoveClass needs to know about some data members of the Game class. Why not make it a function? It's simply too big.
Edit:
What about nested classes? From what I understand, those have to be static? O_o
PHP does not allow for inner classes. Should you wish to access all of the data members from the parent class, I would suggest you employ Inheritance.
A possible alternative:
class OuterClass {
var $x = 15;
function __construct() {
}
}
class ChildClass extends OuterClass {
function __construct() {
parent::__construct();
}
}
You can envoke a method form the parent class by referring to the class itself; In PHP you can do this with the parent keyword. So, to refer to a method in the context of a class rather than an object we use :: as opposed to ->.
in PHP 5.4 or later, you can use PHP Traits which are designed more for multiple inheritance, but may suit your needs. From the PHP Documentation:
A Trait is similar to a class, but only intended to group
functionality in a fine-grained and consistent way. It is not possible
to instantiate a Trait on its own. It is an addition to traditional
inheritance and enables horizontal composition of behavior; that is,
the application of class members without requiring inheritance.
http://php.net/manual/en/language.oop5.traits.php
As mentioned in comments to this answer from another question, the PHP version of this functionality has been added in PHP 7. It does not seem to provide exactly what you are asking for. However, it should provide you a similar design pattern.
Here's the RFC describing how it works: https://wiki.php.net/rfc/anonymous_classes
As mentioned in the other answer's comments, search the RFC page for "nested" to see an example of nesting inside an outer class.
You might want to use a stdClass instead. Here's an SO question about it: What is stdClass in PHP?
You can't nest classes like that.
Look at the "extends" section of the manual.
Is there any advantage to using __construct() instead of the class's name for a constructor in PHP?
Example (__construct):
class Foo {
function __construct(){
//do stuff
}
}
Example (named):
class Foo {
function Foo(){
//do stuff
}
}
Having the __construct method (first example) is possible since PHP 5.
Having a method with the same name as the class as constructor (second example) is possible from PHP version 4 until version 7.
I agree with gizmo, the advantage is so you don't have to rename it if you rename your class. DRY.
Similarly, if you have a child class you can call
parent::__construct()
to call the parent constructor. If further down the track you change the class the child class inherits from, you don't have to change the construct call to the parent.
It seems like a small thing, but missing changing the constructor call name to your parents classes could create subtle (and not so subtle) bugs.
For example, if you inserted a class into your heirachy, but forgot to change the constructor calls, you could started calling constructors of grandparents instead of parents. This could often cause undesirable results which might be difficult to notice.
Also note that
As of PHP 5.3.3, methods with the same name as the last element of a namespaced class name will no longer be treated as constructor. This change doesn't affect non-namespaced classes.
Source: http://php.net/manual/en/language.oop5.decon.php
__construct was introduced in PHP5. It is the way you are supposed to do it now. I am not aware of any advantages per se, though.
From the PHP manual:
For backwards compatibility, if PHP 5 cannot find a __construct() function for a given class, it will search for the old-style constructor function, by the name of the class. Effectively, it means that the only case that would have compatibility issues is if the class had a method named __construct() which was used for different semantics
If you're on PHP5 I would recommend using __construct to avoid making PHP look elsewhere.
The main advantage I see for __construct, is that you don't have to rename your constructor if you change your class name.
Today, the accepted answer is obsolete.
Renaming classes is bad practice: you have to remember what and where to rename everytime you upgrade to newer version. Sometimes (like using Reflection or complex dependence structure) it can be impossible without radical refactoring. And this is accidental complexity you want to avoid. That's why namespaces were introduced into PHP. Java, C++ or C# don't use __construct, they use named constructor and there's no issue with them.
As of PHP 5.3.3, methods with the same name as the last element of a namespaced class name will no longer be treated as constructor. This change doesn't affect non-namespaced classes.
Example
namespace Foo;
class Test {
var $a = 3;
function Test($a) {
$this->a = $a;
}
function getA() {
return $this->a;
}
}
$test = new Test(4);
echo $test->getA(); // 3, Test is not a constructor, just ordinary function
Note that named constructors are not deprecated (PHP 5.5 today). However, you can't predict that your class won't be used in namespace, therefore __construct should be preffered.
Clarification about the bad practice mentioned above (for Dennis)
Somewhere in your code you could use ReflectionClass::getName(); when you rename the class, you need to remember where you used Reflection and check if the getName() result is still consistent in your app. The more you need to remember something specific, the more likely something is forgotten which results in bugs in the app.
The parents can't have control about all the classes in the world which depends on them. If allow_url_include is enabled, some other web might be using the class from your server, which may crash if you rename some class. It is even worse in compiled languages mentioned above: the library can be copied and bundled in other code.
There is no reason why to rename class:
if the class name conflicts, use namespaces
if the class responsibility shifts, derive some other class instead
In PHP classes in namespace, the method with the same name should be avoided anyway: intuitively it should produce an object created the class; if it does something else, why to give it the same name? It should be a constructor and nothing else. The main issue is that the behavior of such a method depends on namespace usage.
There is no issue with __construct constructors in PHP. But it wasn't the smartest idea to alter the named constructors.
The best advantage of using __contruct() instead of ClassName() is when extending classes. It is much easier to call parent::__construct() instead of parent::ClassName(), as it is reusable among classes and the parent can be changed easily.
In your example Foo::Foo is sometimes called a PHP 4 or old-style constructor because it comes from the days of PHP 4:
class Foo {
// PHP 4 constructor
function Foo(){
//do stuff
}
}
PHP 4 constructors will be deprecated but not removed in PHP 7. They will be no longer be considered as constructors in any situation in PHP 8. Future compatibility is definitely a big reason to not use this feature.
Well it has been a few years since this question was asked, but I think I have to answer this one still, because things has changed and for readers in the future I want to keep the information up to date!
So in php-7 they will remove the option to create the constructor as a function with the same name as the class. If you still do it you will get a E_DEPRECATED.
You can read more about this proposal (the proposal is accepted) here:
https://wiki.php.net/rfc/remove_php4_constructors
And a quote from there:
PHP 7 will emit E_DEPRECATED whenever a PHP 4 constructor is defined. When the method name matches the class name, the class is not in a namespace, and a PHP 5 constructor (__construct) is not present then an E_DEPRECATED will be emitted. PHP 8 will stop emitting E_DEPRECATED and the methods will not be recognized as constructors.
Also you won't get a E_STRICT in php-7 if you define a method with the same name as the class AND a __construct().
You can see this also here:
PHP 7 will also stop emitting E_STRICT when a method with the same name as the class is present as well as __construct.
So I would recommend you to use __construct(), since you will have less issues with this in the future.
In PHP 5 the advantage would be that performance would be better. It will look for a constructor by the name of __construct first and if it doesn't find that, it will look for constructors by the name of className. So if it finds a constructor by the name __construct it does not need to search for a constructor by the name className.
Forward compatibility. There's always a chance that legacy code that's left in the language for backwards compatibility's sake will be removed in a future version.
If there is methods __construct and SameAsClassName method then __construct will be executed, SameAsClassName method will be skipped.
I think that the main reason is that is the language convention.
You don't need to force a language to act like someone else.
I mean, in Objective-C you prefix the constructors with -init, for example. You can make your own constructor using your class name but why? Are ther some reason to use this schema instead of the language convention?