In PHP 5.4.9, the following example triggers the fatal error "B has colliding constructor definitions coming from traits".
trait T {
public function __construct () {
echo __CLASS__ . ": constructor called.\n";
}
}
class A {
use T;
}
class B extends A {
use T;
}
There's no problem when the trait contains a different method than the constructor, and no problem when the constructor is actually copied into the classes (without using traits, the "language-assisted copy & paste" feature).
What's so special about the constructor here? Shouldn't PHP be able to figure out that one of them overrides the other? I couldn't find anything about this limitation in the manual.
This related question mentions a way to get around the problem (by using aliases for trait methods), but not what's causing it in the first place.
Try what happens with the following code:
class A {
use T;
use T;
}
Because this is what you effectively wrote by extending from A and then using T again for B.
If you need to use trait T in base and subclasses, use it only in the base-class.
If you need it in subclasses only, use it only in the leaf subclasses.
Related
Consider the following class structures:
trait MyTrait {
public function definedFunction() {
}
}
interface MyInterface {
}
class A {
public function test() {
if ($this instanceof MyInterface) {
// my intelisense tells me that the definedFunction() is not defined
$this->definedFunction();
}
}
}
class B extends A implements MyInterface {
use MyTrait;
}
Could I tell somehow to my intellisense (with doc blocks or anything), that in that specific situation, definedFunction is indeed defined? The above code works, despite intelephense complaining about it, could I disable that complaint with a docblock or something?
On the other hand, is there any other way to restructure my code for intellisense to know about this method? Basically, am I doing something wrong here with this structure?
What I want to achieve is, the following: class A is a template class, which is extended by a bunch of other classes. Some of these other classes, should be able to use some common methods, but not all of them. Because I can not extend multiple classes in PHP, I tried resolving this with traits. If I happen upon one of this kind of classes, I implement an interface with it (to group it somehow for later accessibility), and tell it to use the defined trait, to get all the added functionalities. The function that I call test in the above example, is a function that ALL of the classes that extend class A must be able to access, but when a class implements MyInterface, that function should get some added functionalities. This is why I didn't put that into the trait I am defining.
Why I need to use parent::initialize() on initialize method from Controller, although it works without this?
using: cakephp 3
Thanks
These are php OOP basics: http://php.net/manual/pl/keyword.parent.php
You may find yourself writing code that refers to variables and functions in base classes. This is particularly true if your derived class is a refinement or specialisation of code in your base class.
Instead of using the literal name of the base class in your code, you should be using the special name parent, which refers to the name of your base class as given in the extends declaration of your class. By doing this, you avoid using the name of your base class in more than one place. Should your inheritance tree change during implementation, the change is easily made by simply changing the extends declaration of your class.
class A {
function example() {
echo "I am A::example() and provide basic functionality.<br />\n";
}
}
class B extends A {
function example() {
echo "I am B::example() and provide additional functionality.<br />\n";
parent::example();
}
}
$b = new B;
// This will call B::example(), which will in turn call A::example().
$b->example();
If you need to call is up to your implementation. However, in a framework it is most of the time a good idea to call parent methods when overriding methods, to make sure the logic up in the chain is called. Read the php manual, it comes with examples.
What happens if I use a class in two different traits, and both have a method with the same name but different implementations of this method?
Short answer
(c) AbraCadaver
Long answer
Say you have a class Foo that uses traits A and B:
class Foo {
use A, B;
}
Where both traits have a method with a similar name, but different implementation (the implementation doesn't matter, really):
trait A {
public function bar() {
return true;
}
}
trait B {
public function bar() {
return false;
}
Traits work by extending the class horizontally. Simply put - just adding any new contents to the class. And all works fine till there's any doubling in trait methods and properties. Then you have yourself a fatal error if this conflict is not explicitly resolved.
The sweet part is, you can resolve this conflict by specifying which method from which trait to use:
class Foo {
use A, B {
B::bar insteadof A;
}
}
You can also save the other method from oblivion by using alias for it:
class Foo {
use A, B {
B::bar insteadof A;
A::bar as barOfA;
}
}
The manual has traits farely well documented, go check it out.
I have an object with some protected fields and a method that uses them. The method doesn't do exactly what I need it to do, but I cannot change the original code since I am writing an add-on.
Is it somehow possible to extend the class and override the method so that I could call it on predefined objects of the original class? I thought about monkey patching but apparently it is not implemented in php.
You can override a method by extending the parent class, initiating the new class instead of the parent class and naming your method exactly the same as the parent method, that was the child method will be called and not the parent
Example:
class Foo {
function sayFoo() {
echo "Foo";
}
}
class Bar extends Foo {
function sayFoo() {
echo "Bar";
}
}
$foo = new Foo();
$bar = new Bar();
$foo->sayFoo() //Outputs: Foo
$bar->sayFoo() //Outputs: Bar
I hope below stategy will be works. asume that class is Foo and method is bar(). for override bar() method you have to make customFoo class as mentioned below.
class CustomFoo extends Foo{
public function bar(){
parent::bar();
}
}
I dont know actually what you need because you dont have explained in detail. Still I have tried my best. :)
Try creating a child class that extends the base or parent class that the object currently derives from.
Create a new method with exactly the same name as the method in the Parent class and put your logic in there.
Now instantiate your object from your new class, you would have succeeded in overriding that particular method and still have access to the methods and properties of the base class.
Problem is, once you've loaded the class, you can't officially unload it, and you do need to load it in order to extend it. So it's pretty tied up. Your best bet is to either hack the original class (not ideal) or copy paste the original class definition into a new file:
class ParentClass {
//Copy paste code and modify as you need to.
}
Somewhere after the bootstrapping of your framework:
spl_autoload_register(function ($class) {
if ($class == "ParentClass") { //Namespace is also included in the class name so adjust accordingly
include 'path/to/modified/ParentClass.php';
}
},true,true);
This is done to ensure your own modified class will be loaded before the original one.
This is extremely hacky so first check if the framework you're using has native support for doing this.
I came across this very strange behavior.
The following code
class TestClass {
function testClass() {
echo "Don't show me!";
}
}
$testing = new TestClass;
executes its method testClass without it being called!
However, testClass won't run if renamed into anything else like testClass1.
Is there any hidden 'PHP magic' behind this behaviour?
EDIT.
At the end I see this question is trivial to ninjas grown up with PHP. As recent newcomer to PHP, I've learned to use __construct as constructor. With that "relic behaviour" carefully removed from modern tutorials. I am so glad people realized how terrible it was, changing class name and forgetting to change that of the constructor - what a nightmare!
Pre-PHP5, the __construct method was not used as the class constructor. Instead, a method with the same name as the class was used.
From the documentation:
For backwards compatibility, if PHP 5 cannot find a __construct() function for a given class, and the class did not inherit one from a parent 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.
Creating a (empty) constructor (method named __construct) will stop the message from being echoed upon class initialization (only needed for < PHP 5.3.3 *):
class TestClass {
function __construct() {
}
function testClass() {
echo "Don't show me!";
}
}
* 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.
In older versions of PHP a method with the same name as the classname was considered the constructor.