Working in a symfony model, I want to override a function and call the overridden function from within the overriding one, along the lines of
class MyClass extends BaseMyClass {
function setMyProperty($p) {
parent::setMyProperty($p);
//do some other stuff
}
}
This is resulting in a segmentation fault. I don't want to alter the parent class - it's been generated by symfony, and may feasibly be overwritten in the future if the model is rebuilt. This seems like something that should be straightforward, but I'm struggling to find the solution.
Since you saw the problem, I guess you should mark it as answered to remove it from the unanswered list.
I've managed to find a solution to my own question on the symfony project forum.
I can't call the overridden function because it doesn't exist. Though it exists enough for me to override it.
Using
$this->_set('my_property', $p);
Works where
parent::setMyProperty($p);
Causes the error.
Note that
$this->setMyProperty($p);
Works fine in my class if the method has not been overridden.
Related
I'm new to Yii2 and returning to PHP dev after a very long time. I have an extensive background in Java development. I stumbled onto this recommendation in the docs for ActiveRecord:
__construct() public method
Defined in: yii\base\BaseObject::__construct()
Constructor.
The default implementation does two things:
Initializes the object with the given configuration $config.
Call init().
If this method is overridden in a child class, it is recommended that
the last parameter of the constructor is a configuration array, like
$config here.
call the parent implementation at the end of the
constructor.
My question is about the last sentence:
call the parent implementation at the end of the constructor.
As a Java dev, this advice seems very weird to me. In Java, not only is it recommended to call the parent constructor as the very first call from your overridden constructor, this is even enforced and it's actually impossible to do it any other way. Either your parent constructor is called first implicitly, or, if you make an explicit call, it MUST be the very first statement in your method. This is enforced by the compiler.
Theoretically, this makes a lot of sense to me. Because as long as you did not call the parent constructor, your parent class did not have the chance to initialize, so any code you write in the constructor before calling the parent constructor would be working with a half-initialized object.
Looking at some SO answers I found, they seem to be going against the advice in the official docs and call the parent::__construct before their own custom logic, as I would expect it. For example, the accepted answer in the question How can I create a constructor in a Yii2 model shows an example where they call the parent first:
function __construct()
{
parent::__construct();
...
}
Another answer in that same question that does follow the official docs' advice scores 0 points:
public function __construct($config = []) {
// your init code here
// ...
parent::__construct();
}
Looking at the article about calling the parent constructor on phptutorial.net, they show an example where they call the parent first, as I would expect it:
class SavingAccount extends BankAccount
{
private $interestRate;
public function __construct($balance, $interestRate)
{
parent::__construct($balance);
$this->interestRate = $interestRate;
}
// ...
}
As I said my PHP is quitte rusty and I am a Yii2 n00b, so I was hoping to get some clarification here about this quitte fundamental thing that is still not clear to me after reading docs, tutorials and SO posts for a few hours now. This investigation was triggered by seeing the constructor being called both first and last very inconsistently in the codebase that I inherited and am currently working on.
In PHP, is there an official recommendation for when to call the parent constructor?
Is the advice to call the parent constructor last also in other PHP frameworks?
Hoping not to incite opinion-based discussion, so please quote official references, point to official docs of other projects etc.
#michal-hynĨica correctly stated the reason for your ambiguity(Worthy of votUp). But since you mentioned that the official reference, on the same page (BaseObject), this issue is explicitly stated: line
In order to ensure the above life cycles, if a child class of BaseObject needs to override the constructor,
....
of the constructor, and the parent implementation should be called at the end of the constructor.
According to the description of this link (similar to your question):
init () is called which further calls bootstrap () to run bootstrapping components.
As a result, this is done to ensure configuration.
The same process is done in the controller class and the main module.
Of course, there are many examples like this on the php site (depending on the need)
Also read lifecycles and entry script in yii. components and structure-applications. Good luck
I'm working on a WordPress project. There is a child theme implemented, and the parent one has a class to show authors' links. We have implemented a feature to support multiple authors per post, then we have our own methods for showing the proper links (not a single-author link, but many links joined depending on the authors count).
The complete scenario:
Theme: Newspaper
File: td_module.php (includes/wp_booster/td_module.php)
Class: td_module (abstract, many other classes in the parent theme inherit this one)
Method: get_author()
There are many other classes inheriting td_module in the parent theme, hence I cannot just extend td_module in my child theme since every change to the parent theme would be lost when the theme gets updated
Somehow I need to expand this method to show something different, but I don't want to change the method in the td_module class: even when it would be the fastest / most secure solution, this code would be overwritten on every theme upgrade.
This method is widely used in the Theme, that's why is that important to add some code here.
Why I still have some hope: There is a WP filter td_wp_booster_module_constructor, being called on the constructor of td_module class. The problem is that this class doesn't have any other filter on the method for showing the authors, but just the td_wp_booster_module_constructor filter call on the constructor.
The base PHP (and OOP) question: is it possible to expand / replace a method by using this filter in the constructor somehow?
Some code to clarify:
abstract class td_module {
...
function __construct($post, $module_atts = array()) {
...
// Can I change the get_author behavior by using this filter?
apply_filters("td_wp_booster_module_constructor", $this, $post);
// This is the only filter available in the entire class!
...
}
...
function get_author() {
$buffy = '';
// Code for generating author link ($buffy .= ...)
...
// This function doesn't have any apply_filter, there are no filters available
return $buffy;
}
}
Basically, you can't modify a class definition at runtime. The fact that you have a filter available on the constructor is a red herring and really not relevant.
Either the get_author() has some facility to change it's behaviour from outside class definition (in Wordpress parlance, filter and action hooks), or you simply cannot do it.
Outside of Wordpress, in an application with a proper dependency inversion container, you should probably do this by decorating the class and having all class consumer use the decorated class.
But since you have no way of telling class consumers to use one or the other, and a lot of code out of your control is presumably instantiating the class directly, something like this simply won't fly.
There is one extension, Runkit, that allows for changes of behaviour and definitions at runtime. there is even a method to modify a method definition. although I have not tried the extension, and do not know if it runs in an updated PHP runtime.
Note it is almost certainly a very bad idea to do this on production code, and that since you are dealing with code out of your control anyway you can't even be sure you would be changing the definition before it's used for the first time.
I've also found a repo for Runkit that says that it almost works on PHP 7, if you are absolutely convinced on going that way.
Your issue is that the base class is vendor code which you did not write.
So create a class in between your classes extending it!
Job done!
<?php
class SomeWordpressCrap
{
public function doSomething()
{
return 'something';
}
}
class YourAwesomeNewClass extends SomeWordpressCrap
{
public function doSomething()
{
return 'something better!';
}
}
class OneOfYourExistingClasses extends YourAwesomeNewClass
{
}
UPDATE So it turns out the OneOfYourExistingClasses is also vendor code, so the above solution will not work.
However! You could use Roave's "Better Reflection" lib, which you can find here https://github.com/Roave/BetterReflection
This will allow you to "Change the body of a function or method to do something different", which I believe is exactly what you need. Good luck!
I have looked online for the meaning of parent::init(); . All I was able to find was that init() is to initialize some settings which want to be present every time the application runs.
Can anyone please explain the meaning of parent::init() in exact sense, like significance of both the words?
Thanks in advance.( I am sorry if its too simple! )
When we use parent::init(), we are just calling the parent method (in this case init()) inside a method of the current class.
About parent::
For example, let's say we have a class called MyClass. This class have a awesome method that runs alot of things:
class MyClass
{
public function runStuffs()
{
// trigger events, configure external stuff, adding default values to properties.
}
}
Now, after some time, we decided to create a new Class that extends from the first one. And we called MySecondClass:
class MySecondClass extends MyClass
{
}
It already have the method runStuffs(), but, for this second class, we need to do more things in this method, but maintaining what it have.
Sure we could rewrite the whole method and just copy and paste what we have in MyClass and add the new content. But this isn't elegant or even a good practice. what if later on We change the method in MyClass, you probably would like that MysecondClass have that changes too.
So, to solve that problem, we can call the parent method before write your new content:
class MySecondClass extends MyClass
{
public function runStuffs()
{
parent::runStuffs();
// do more things!
}
}
Now MySecondClass->runStuffs() will always do what its parent do and, after that, more stuff.
About the init() method.
init() is a method used in almost all classes from Yii2 framework (since most of then extends from yii\base\Object at some point) and works just like the __constructor() method (native from PHP). But there is some differences, you can read more here.
Actually the init() method is called inside the __constructor(), and the framework encorage us to use init() instead of __construct() whenever is possible.
Now if both are pretty much the same thing, why do they create this method? There is an answer for that here. (take a look at qiang's answer, from the dev team):
One of the reasons for init() is about life cycles of an object (or a component to be exact).
With an init() method, it is possible to configure an object after it is instantiated while before fully initialized. For example, an application component could be configured using app config. If you override its init() method, you will be sure that the configuration is applied and you can safely to check if everything is ready. Similar thing happens to a widget and other configurable components.
Even if init() is called within constructor rather than by another object, it has meaning. For example, in CApplication, there are preInit() and init(). They set up the life cycles of an application and may be overridden so that the customization only occurs at expected life cycles.
Conclusion
So, when you use a init() method and calls parent::init() you are just saying you want to add more things to that method without removing what it already was doing.
The parent::init(); Method is useful to execute a code before every controller and action,
With an init() method, it is possible to configure an object after it is instantiated while before fully initialized.
For example, an application component could be configured using app config.
If you override its init() method, you will be sure that the configuration is applied and you can safely to check if everything is ready.
Similar thing happens to a widget and other configurable components.
In Yii, init() method means that an object is already fully configured and some additional initialization work should be done in this method.
For More Information check this link :
https://stackoverflow.com/questions/27180059/execute-my-code-before-any-action-of-any-controller
Execute my code before any action of any controller
might be helpful to you.
To make it simple, I have noticed that PHP doesn't seem to offer any magic constant for determining what the name that a trait has been changed to in a class. Since this sounds confusing to me in words, I will give an example, as it is rather easy and would expect it to be somewhere in the new PHP 5.5, I don't see a way to doing it. So here it is:
Say we have some class, that uses some trait that conflicts with some function inside the class, example:
class SomeClass {
use \Name\Space\SomeTrait { SomeFunction as private NewFunctionName; }
function SomeFunction() {
$this->NewFunctionName();
}
}
Since, obviously this class has the "SomeFunction" function, and we are aware that inside of SomeTrait we have included, is a function that is matching by name to a function we have inside this class. Now, since the "SomeFunction" came into this class via a trait inside of a \Name\Space, these 2 functions do 2 different things, but happen to use the same name, and inside of either another function or literally our 'SomeFunction', we then use the "SomeFunction" from our trait, by calling it by the "NewFunctionName".
So hopefully I haven't lost anyone here, as here is what my question comes down to in the above scenario. Within the \Name\Space\SomeTrait\SomeFunction(), how could one get the "NewFunctionName" that this trait function was assigned too? One would think to use a magic method, such as __FUNCTION__, or __METHOD__, or even __TRAIT__, except none of these give the expected result, so does anyone know a way to get this information without passing it to the function as a parameter and resulting in a hacky code? Maybe PHP 5.6 needs to add a new Magic Constant __AS__, or adjust the result of __TRAIT__, I dont understand why __TRAIT__ and __FUNCTION_ need to return the same information (or nearly the same information). Any help would be awesome, if it is an unconventional hacky method, Im interested in seeing my options, until I can open up a bug report with php regarding this. (if it is truly a bug)
edit:
My current, least hacky, method seems to be,
debug_backtrace()[0]['function']
and though it works, I feel it is doing a lot to get a simple string, especially if you use the function a lot. :/
This is the solution I ended up using. It's not very good but probably better than using the debug_backtrace function.
Problem example:
Trait ExampleTrait {
protected function doSomethingRecursive() {
// this is a problem because it could be renamed
$this->doSomethingRecursive();
}
}
Solution example:
Trait ExampleTrait {
protected function doSomethingRecursive() {
// this is a problem because it could be renamed
$this->__internal_doSomethingRecursive();
}
private function __internal_doSomethingRecursive() {
// this works because the class would have
// used and renamed the above function
// but this "internal" function *should*
// remain available under it's original name
$this->__internal_doSomethingRecursive();
}
}
Of course it's possible to break this but for most cases it should be fine. You could also include the name of the trait in the internal function name to further prevent conflicts.
Your current solution is going to be the best, with a couple tweaks:
debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS,1)[0]['function']
The DEBUG_BACKTRACE_IGNORE_ARGS and the frame limit of 1 there will make the backtrace shallow, faster, and use less memory.
A word before my question to say I am pretty new to OOP in PHP, and I'm very grateful to the site, and you all for reading - and sometimes answering beautifully (as you can see here or here, or even here) and helping big time my late (sort of) improvement dealing with classes.
All my previous questions lead me today to this one:
In a class extending PDOStatement, how can I trigger a default action each time one of the parent public methods is called?
I can do this:
class genc_query extends PDOStatement{
public function rowCount(){
$this->myDefaultAction();
return parent::rowCount();
}
}
But as I need to change in the same way almost all of the native methods, I wonder if there's no way to trigger a function like __call() as if these methods were private (as it's not possible to make them private).
as it's not possible to make them private
Indeed, this seems to be the case.
ReflectionMethod can let you change the accessibility of a method, but it seems that it either doesn't work on internal methods (i.e. not user-defined) or it won't set public methods to protected/private. It seems designed to make protected/private methods public instead.
It looks like your copy-and-paste boilerplate inside each method is going to be necessary. Besides __sleep and __wakeup, there are only about three dozen methods, so it should only take you a few minutes.
For the sake of clear code, extend every method (means: overwrite and call parent::method() there), that you wants to have additional behaviour. Else there will be some day, where you or someone else may get really confused on what happens there.