Situation:

class A extends etc { public function init() { parent::init(); //... } } class B extends A { public function init() { parent::init(); //... } } class C extends B { public function init() { parent::init(); //... } } 

I need to execute the init () method in C but in such a way that parent :: init () (parent method) is not executed, but all the other init () along the inheritance chain are executed.

those. the init () method was executed in C and then in A and then everything went along the chain. How can I skip the execution of the init () method in B without changing it?

UPDATE: forgot an important detail. we don't know the name of the progenitor class

UPDATE 2: Why did such an idea even appear: Php. Modification of class logic during initialization and parents

  • Better tell me why you need it - ilyaplot
  • one
    You can call A::init() , however, it is not worth the C class to know about the details of the hierarchy structure. - user236014
  • stackoverflow.com/questions/1557608/… there is another example where you pass an optional parameter through which you decide which father methods to use - Oleksandr
  • That is, public function init($bypass = false) { parent::init(); if (!$bypass) { //.. } } public function init($bypass = false) { parent::init(); if (!$bypass) { //.. } } , and in class С pass the parameter that you do not want to use it $bypassPapa = true; parent::init($bypassPapa); $bypassPapa = true; parent::init($bypassPapa); - Oleksandr
  • @Oleksandr, you propose to change the method of the parent, and this cannot be done according to the conditions of the problem. - Stanislav Belichenko February

3 answers 3

Without being distracted by the author’s censure for poor architecture,
option using get_parent_class :

 class C extends B { public function init() { $grandPa = get_parent_class(get_parent_class($this)); $grandPa::init(); } } $c = new C; $c->init(); 

Works in php> = 5.3


No one can guarantee the correct operation, because the developer of class B, certainly hoped that the initialization method will be called.

Ask yourself, why do you need an uninitialized class B and can you inherit your class directly from A ?


The second question to ask is: why did you need to skip the method?

Probably, the author of class B allowed himself some third-party effects in this method, for example, a conclusion.

Then we can try to eliminate these side effects:

  public init() { ob_start(); parent::init(); $output = ob_get_clean(); } 
  • the author asked for this and in order to understand, among other things, maybe a problem in architecture. I can't change my parents. are they at vendor - WebCoder
  • What are you about yourself in the third person? Who is author? - vp_arth
  • I answered questionable in comments. Why do I need class B uninitialized? and why did you decide that he is. I will simply change the initialization in my class C method which will do everything in class B but slightly modify it - WebCoder
  • You mix responsibility. For the initialization of the members that the class B contributes is responsible class B What to do with private members? And if the implementation changes after the next composer update will you re-align everything? - vp_arth
  • one
    If you specified more specific data, what is the hierarchy, what needs to be changed, then you could advise something. I think it is worth creating a separate question for this. - vp_arth

Three options:

a) Refer to the method of grandfather directly:

 class A extends etc { public function init() { parent::init(); //... } } class B extends A { public function init() { parent::init(); //... } } class C extends B { public function init() { A::init(); //... } } 

b) Use call_user_func() as a whole in the same code.

c) Use ReflectionMethod::invoke , taking logic out of classes. They will look like yours in your example code, and already in using them in the code there will be a construction of the form:

 $С=new С(); $reflectionMethod = new ReflectionMethod(get_parent_class(get_parent_class($С)), 'init'); $reflectionMethod->invoke($С); 

But in general, there is also a fourth option, the most correct one is to change the logic of your application, since on the one hand, there is no method in php to contact the "grandfather" in some native way, but on the other hand all of the above options are terrible crutches.

  • one
    I read everything, thanks, but I would solve the problem at the design stage of the class. the solution at runtime when creating instances of a class is slightly not what we would like. I understand that probably an error in the structure / approach of mine. The first time such a need arose, I guess I want what I want to be wrong / wrong .. I will think about the 4th option - WebCoder
  • @WebCoder Yes, the solution is wrong at the design level, in my opinion. And so it is clear that I want another option :) - Stanislav Belichenko

I suspect there must be something like this ...

 <?php class A extends etc { public function init($pars = array()) { if (!in_array(__CLASS__, $pars)) echo 'A<br>'; parent::init($pars); } } class B extends A { public function init($pars = array()) { if (!in_array(__CLASS__, $pars)) echo 'B<br>'; parent::init($pars); } } class C extends B { public function init($pars = array()) { if (!in_array(__CLASS__, $pars)) echo 'C<br>'; parent::init($pars); } } $t = new C(); $t->init(['B']); 
  • I can not change parents and grandparents. for they are in vendor - WebCoder
  • All these details, as well as a clearer formulation of the problem (question) need to be described immediately ... then you will get immediately (or very quickly) a solution that will meet exactly the needs. - Stanislav
  • "How can I skip the execution of the init () method in B without changing it?" - it was written right away - WebCoder