How to run code upon class definition (not object instantiation) - php

I'm looking for a way to transparently run code when a class is defined - more importantly, when the class is extended.
For example, if I have:
class A
{ function define()
{ echo "A has been defined!\n";
}
__magicDefine
{ define();
}
}
class B extends A
{
}
I'd like that to print "A has been defined!\n". Is this impossible?

That would be impossible, yeah. Nothing gets called on class definition.
This concept is even sort of aggressively unsupported; try writing
class foo {
static function __construct() {
echo "hi!";
}
}
and you'll get Fatal error: Constructor blah::__construct() cannot be static.

I guess what you're trying to do is keep track of objects that are running? Not exactly sure what your end goal is here.
Perhaps you're looking for the ReflectionClass at run time? You can determine if a class exists and what the extended class is.
It also sounds like what you're aiming for is an object factory that keeps track of objects that are being used. Look up singletons, factory, and static member functions/variables concepts for those.
As for this:
class A
{
public function __construct()
{ print "A has been called";
}
}
if class B overrides the constructor, it's not going to call A's constructor. Ex:
class B extends A
{
public function __construct()
{ print "B has been called";
// parent::__construct(); /// would print out A has been called
}
}
However in code, you can check if B is an instance of A one of many ways:
function doSomethingWithA(A $a)....
function doSmoethingWithA($a)
{
if($a instanceof A)
{
// blah
}
}
Don't know if that helps much.

In Java, this is possible, by using a "java agent" which would register a java.lang.instrument.ClassFileTransformer with the JVM.

Related

PHP OOP extend class or pass it as parameter

i am confused a little, well for a long time, i've used PHP classess in this way:
class A {
private $temp;
public function __construct() {
for($i=0; $i<=300000; $i++) { $this->temp[ $i ] = "Nedzad Alibasic"; }
}
}
and then another class which contains parameter in construct where i would pass class A as declared model:
class B {
private $a;
public function __construct($a) { $this->a = $a; }
}
And everything was fine, i could easy refer to class A by $b->a->somefunction(); but always it seemed to me, when i allocate A class to B, i would charge extra memory, because i passed the whole class? But how do i see it, there's almost no difference between passing and extending class?
I mean, is there someone who can lead me why should i switch from this way to class B extends A { /** code **/ } when there's almost no difference in memory?
Or there's something else usefull i could use with extends, but can't use within passing class as parameter.
Best regards.
The advantage of extending instead of wrapping inside an attribute of the class is that, when you extend, you are saying that B is also of type A, which means that everywhere in your code where needs an A class, B could be used if B extends from A.
<?php
class A {
private $temp;
public function __construct() {
for($i=0; $i<=300000; $i++) { $this->temp[ $i ] = "Nedzad Alibasic"; }
}
public function getTemp(){
return $this->temp;
}
}
class B extends A{
public function __construct() {
parent::__construct();
}
}
function showFirstElementOfTemp($object){
if($object instanceof A){
echo $object->getTemp()[0];
}else{
echo "Not an A";
}
}
$b = new B();
showFirstElementOfTemp($b); //Outputs "Nedzad Alibasic"
As you can see, this works, because B is an A, and passing B as a parameter in a function where we check the instance and ensure we have a type of A, B is also accepted.
Other than that, wrapping an A for having access to it's methods and attributes is the same, except that you won't get this hierarchy of types that you have with inheritance.
What you're used to doing is a form of composition, whereas using extend is, of course, inheritance. Generally composition is to be preferred over inheritance. You should probably continue doing. There are loads of resources describing the pros and cons of composition versus inheritance; picking a good one is tricky but I recommend you read a few of them.

Invoke inherited member functions using $this->my_func() or parent::my_func()?

I've been creating abstract classes and interfaces to force consistency within my Wordpress plugins, but I'm never sure if I should be invoking inherited functions by using parent::some_function() or using $this->some_function()? Since jumping back and forth between the two looks super messy/confusing.
For Example:
Using getter/setters should I be:
$this->get_my_var(); // indicating nothing about its origins except through comments
or
parent::get_my_var(); // indicating you can find it in the parent
They're not the same thing.
class A {
protected function foo() {
return "a";
}
}
class B extends A {
protected function foo() {
return parent::foo() . "b";
}
public function bar() {
return $this->foo();
}
}
$b = new B();
var_dump($b->bar()); // "ab"
If instead you had:
class B extends A {
...
public function bar() {
return parent::foo();
}
}
var_dump($b->bar()); // just "a"
The foo function of B adds something to the foo function of A. This is a common pattern.
Whether calling parent::foo in bar is good or not depends on your design choices, I personally think it's a little iffy. Calling parent::foo in foo is fine by the way.
I only use parent:: in constructors, destructors and static methods. For everything else I trust people to know how object inheritance works. I would use $this->get_my_var();

Overriding methods in PHP?

In other OO languages like Java we can override a function, possible using keywords/annotations like implements, #override etc.
Is there a way to do so in PHP? I mean, for example:
class myClass {
public static function reImplmentThis() { //this method should be overriden by user
}
}
I want user to implement their own myClass::reImplementThis() method.
How can I do that in PHP? If it is possible, can I make it optional?
I mean, if the user is not implementing the method, can I specify a default method or can I identify that the method is not defined (can I do this using method_exists)?
<?php
abstract class Test
{
abstract protected function test();
protected function anotherTest() {
}
}
class TestTest extends Test
{
protected function test() {
}
}
$test = new TestTest();
?>
This way the class TestTest must override the function test.
Yes, there is. You have the option to override a method by extending the class and defining a method with the same name, function signature and access specifier (either public or protected) it had in the base class. The method should not be declared abstract in the base class or you will be required to implement it in the derived class. In you example it would look something like this:
class MyClass {
public static function reImplmentThis() { //this method should be overriden by user
}
}
class MyDerivedClass extends MyClass {
public static function reImplmentThis() { //the method you want to call
}
}
If the user does not overrides it, MyDerivedClass will still have a reImplmentThis() method, the one inherited from MyClass.
That said, you need to be very careful when invoking extended static methods from your derived class to stay out of trouble. I encourage you to refactor your code to extend instance methods unless you have a very specific need to extend static classes. And if you decide there is no better way than extending static classes please be sure to understand Late Static Binding pretty well.
Yes, its possible to check if the method is implemented or not and get a whole lot more of information about a class using PHP Reflection.
This touches on several OOP subjects.
First, simply overriding an method declared in a parent class is as simple as re-declaring the method in an inheriting class.
E.g:
class Person {
public function greet(string $whom) {
echo "hello $whom!";
}
}
class Tommy extends Person {
public function greet(string $whom = "everyone") {
echo "Howdy $whom! How are you?";
}
}
$a = new Tommy();
$a->greet('World');
// outputs:
// Howdy World! How are you?
If on the overriding method you wan to reuse the logic of the overriden one, it's just a matter of calling the parent's method from the extending class::
class Tommy
{
public function greet(string $whom)
{
// now with more emphasis!!!
echo parent::greet(strtoupper($whom)) . "!!!!";
}
}
Now Tommy::greet() calls Person::greet(), but modifies the result before returning it.
One thing to note is that overriding methods have to be compatible with the overriden one: the method visibility can't be more restrictive than the original one (it's OK to increase visibility), and the number and type of required arguments can't conflict with the original delcaration.
This works, because the type of the arguments does not clash with the original, and we have less required arguments than on the parent:
class Leo extends Person {
public function greet(string $whom = "gorgeous", string $greet = "Whatsup" ) {
echo "$greet $whom. How are you?";
}
}
But this doesn't, since there are additional required arguments. This would make impossible to switch the original class for this one transparently, and thus would throw a Warning:
class BadBob extends Person {
public function greet(string $whom, string $greet ) {
echo "$greet $whom. How are you?";
}
}
Additionally, you mention in your question that "this method should be overriden by the user". If you require client classes to actually implement the method, you have a couple of options:
Abstract classes & methods
These are methods where the implementation is left empty, and that extending classes have to implement to be valid. In we changed our original class Person to:
abstract class Person {
public function greet(string $whom) {
echo "hello $whom!";
}
public abstract function hide();
}
Since now the class contains an abstract method, it needs to be declared as an abstract class as well.
Now it is not possible to instantiate Person directly, you can only extend it in other classes.
Now all our existing Person extending classes would be wrong, and trying to execute the previous code would throw a fatal error.
An example of a valid class extending Person now would be:
class Archie extends Person {
public function hide() {
echo "Hides behind a bush";
}
}
Any class that extends Person must declare a public hide() method.
Interfaces
Finally, you mention interfaces. Interfaces are contracts that implementing classes have to fulfill. They declare a group of public methods without an implementation body.
E.g.:
interface Policeman {
public function arrest(Person $person) : bool;
public function help($what): bool;
}
Now we could have class that extended Person and implemented Policeman:
class Jane extends Person implements Policeman {
public function hide() {
echo "Jane hides in her patrol-car";
}
public function arrest(Person $person): bool{
// implement arrest method
return false;
}
public function shoot($what): bool {
// implements shoot() method
return false;
}
}
Importantly, while it's possible to extend only one class (there is no multiple inheritance in PHP), it is possible to implement multiple interfaces, and the requirements for each of those have to be fulfilled for the class to be valid.

Calling parent method of inherited class from base class

The following example does not work because when parent is called in class A, php looks for the parent class of class A but it doesn't exist. I would rather this line to call Test() in class B.
Is this possible?
(I know this seems like a stupid example but it has a practical application)
abstract class A {
function CallParentTest()
{
return call_parent_method('Test');
}
}
abstract class B extends A {
function Test()
{
return 'test passed';
}
}
class C extends B {
function Test()
{
return $this->CallParentTest();
}
}
$object = new C();
echo $object->Test();
Thanks!
EDIT
I changed the parent keyword to the made up method call_parent_method because I think that may have been confusing people. I know there is no way to do this using the keyword.
Just as David Harkness pointed out, I am trying to implement the Template Method pattern but instead of using two different method names, I'm using one. B::Test() will be the default method unless substituted with alternate functionality.
You can use reflection to bypass the natural calling order for overridden methods. In any context simply create a ReflectionMethod for the method you'd like to call and invoke it. You don't need to do this from the class itself, but you will need to call setAccessible(true) if the method isn't public.
class A {
public function bypassOverride() {
echo "Hi from A\n";
$r = new ReflectionMethod('B', 'override');
$r->invoke($this);
}
}
class B extends A {
public function override() {
echo "Hi from B\n";
}
}
class C extends B {
public function override() {
echo "Hi from C\n";
$this->bypassOverride();
}
}
$c = new C;
$c->override();
The output from this is
Hi from C
Hi from A
Hi from B
You could make bypassOverride() more generic and move it to a helper class if you need to do this a lot.
Is this possible?
No.
It makes no sense to use the parent keyword except in child classes. It's only purpose is to be used by child classes to call methods that it as overridden. Think about multi-level parent calls where a child calls its parent's method of the same name and, in turn, that parent calls its parent's method of the same name.
webbiedave is correct regarding parent, but it looks like you're trying to implement the Template Method pattern where the abstract base class calls a method that subclasses are expected to implement. Here's an example that demonstrates a horrible way to handle errors in your applications.
abstract class ExceptionIgnorer {
public function doIt() {
try {
$this->actuallyDoIt();
}
catch (Exception $e) {
// ignore the problem and it might go away...
}
}
public abstract function actuallyDoit();
}
class ErrorThrower extends ExceptionIgnorer {
public function actuallyDoIt() {
throw new RuntimeException("This will be ignored");
}
}
$thrower = new ErrorThrower;
$thrower->doIt(); // no problem
Here doIt() is the template method as it defines the overall algorithm to follow.

Object of class A cannot be create directly but only by class B

class A
{
public function foo()
{
}
}
class B
{
$a = new A;
public function go()
{
}
}
I want A object cannot be created directly.But only by class B.
How i can do this.
Why would you need that?
Remember - a class is a defacto factory for objects, and the object should do things, and it should do them with passed params and available instance variables which means you should pass everything the object needs to the constructor and you should not care about the fact that the object can be created by everybody.
Seriously.
Sounds like you want to extend an abstract class.
abstract class A {
protected function foo() {
echo "Hello world!";
}
}
class B extends A {
public function go() {
$this->foo();
}
}
$obj = new B;
$obj->foo(); // error - cannot call a protected method directly
$obj->go(); // echo's "Hello world!"
If you really want to do this, check factory design pattern. I think it will what you are asking for. There we will have a separate factory class for managing object creation.

Categories