PHP - dynamically extend parent class with static methods - php

consider the following:
class A
{
public static function bark()
{ echo 'woof'; }
}
class B extends A
{
public static function speak()
{ echo 'hello'; }
}
A::speak();
// Fatal error: Call to undefined method A::speak()
How is one supposed to extend a class with methods that you need to be globally available within that class with methods that are not yet known, but are loaded at run-time, depending on the flow of your application?
Yes sure we can make traits and put use in the class like:
trait B
{
public static function speak()
{ echo 'hello'; }
}
class A
{
use B;
public static function bark()
{ echo 'woof'; }
}
A::speak();
// hello
but then use B is not called dynamically, hence you will have to update class A with every new trait available - manually.
This is absurd, why force developers to break their brain in trying to accomplish something so fundamentally simple?
Does anyone have an idea how this can be done in a clean way? I mean I have seen some impressive methods by using Singletons, namespaces, callbacks and the works, but in each case it requires a lot more code and repetitive programming than what is really needed.
Either that or i'm missing the boat completely haha!
Thanks in advance, your help will be appreciated and voted generously.

I think with some creativity you could make use of the __call magic method.
You could do something like this:
class A
{
/**
* #var array
*/
protected $methods = [];
public function __call($name, $arguments)
{
if (!empty($this->methods[$name]) && is_callable($this->methods[$name])) {
return call_user_func_array($this->methods[$name], $arguments);
}
}
public function addMethod($name, Closure $method)
{
$this->methods[$name] = $method;
}
}
// get class instance (A have no methods except of addMethod)
$instance = new A();
// add methods on runtime
$instance->addMethod('sum', function($num1, $num2) {
return $num1 + $num2;
});
$instance->addMethod('sub', function($num1, $num2) {
return $num1 - $num2;
});
// use methods exactly the same way as implemented fixed on class
echo $instance->sum(2, 2);
echo $instance->sub(3, 2);
Of course you could use also __callStatic for static methods. And if you want to get it a bit more complex also could use the concept of Dependency Injection to add objects instead of methods. Then search the called method through the injected objects and call it when it's found.
I hope this give you at least a good idea.

Related

PHP class with static methods, before hook

I have the following class in PHP with all static methods:
class Foo {
public static function a {
}
public static function b {
}
public static function c {
}
public static function d {
}
public static function e {
}
}
Is there a way to create a hook to fire before calling any of the methods in class Foo i.e. like a before hook? I need some logic, and don't want to have to add that logic to every static function like:
class Foo {
private static function init() {
// pre logic here
}
public static function a {
Foo::init();
}
public static function b {
Foo::init();
}
public static function c {
Foo::init();
}
public static function d {
Foo::init();
}
public static function e {
Foo::init();
}
}
What you want is called an Aspect-Oriented Programming. It allows to define an advice before method call, property access, class initialization, etc.
However, this technique is not used widely in PHP due to its complexity. I can suggest your an example with Go! AOP Framework.
class AutoInitializationAspect implements Aspect
{
/**
* This advice intercepts an execution of static methods
*
* We use "Before" type of advice to initialize the state
*
* #param MethodInvocation $invocation Invocation
*
* #Before("execution(public Foo::*(*))", scope="target")
*/
public function beforeMethodExecution(MethodInvocation $invocation)
{
$class = $invocation->getThis(); // will be the class name
$class::init(); // access to the private scope of class
}
}
Visit http://demo.aopphp.com/?showcase=loggable for demo (see LoggingDemo::runByName() static method intercepted)
I guess you can use __callStatic() magic method to achieve.
public static function __callStatic($name, $arguments)
{
// pre logic here
switch($name)
{
case 'a':
// do something
break;
case 'b':
// do something
break;
}
}
Basic answer: no, there is no such thing in plain PHP.
However, you can try several options:
You can call your methods like aSomeSuffix, bSomeSuffix, etc., and call them via __callStatic method computing that suffixed name on-the-fly.
Pros:
Single handler
Cons:
Your IDE won't see those methods until you explicitly write them down via phpDoc
Extra work and big pile of places to make a mistake (arguments passing by reference, missing method handling, etc.)
You can try Go library that introduces aspect-oriented programming in PHP claims to be able to intercept static calls. I've never used it (though i've heard lots of good responses about it) and don't know anything about performance drops and/or caveats using it, but it seems to be matching your case. I guess, this would still require to write an annotation for every method, but it will result in single handler.
Call initialization method in every method. This is what you're trying to avoid and not an option, i guess, just because it's violates DRY.

design pattery strategy with access to parent class

I want to implement the strategy design pattern using php:
interface dummy_function {
public function render();
}
class a implements dummy_function {
public function render() {
echo "class a\n";
// I want to acess x_main::dummy like: echo parent::dummy
}
}
class b implements dummy_function {
public function render() {
echo "class b\n";
// I want to acess x_main::dummy like: echo parent::dummy
}
}
class x_main {
public $dummy = "hello world";
public function setX_Function( dummy_function $funcname ) {
$this->x_function = $funcname;
}
public function render() {
$this->x_function->render();
}
}
$test = new x_main();
$test->setX_Function( new a() );
$test->render();
Inside my classes I want to access to some methods and variables defined in the main class. Unfortunatelly "parent" does not work to access contents from the class "x_main" inside the implementation classes.
A way i found is to give $this as parameter to the method "render", like:
class x_main {
[...]
public function render() {
$this->x_function->render( $this );
}
}
class a implements dummy_function {
public function render( $mainclass ) {
echo "class a\n";
echo $mainclass->dummy;
}
}
The next way i testest is to set the variable from the class main direcly into the implemented function, like:
class x_main {
[ ... ]
public function setX_Function( dummy_function $funcname ) {
$this->x_function = $funcname;
$this->x_function->dummy = $dummy;
}
}
class a implements dummy_function {
public function render() {
echo "class a\n";
echo $this->dummy;
}
}
Both solutions work, but I feel a bit confused if that's the best way to implement my desired idea. It looks extremly like a workaround but not like a real OO-programming.
I'm looking forward for your ideas.
Rehashing the comments above:
The two classes aren't related in any way, they certainly don't have a
parent relationship. One object holding an instance of another object
does not mean these two objects are in any sort of relationship with
one another. You simply need to explicitly pass data into your
dummy_function instance; e.g.: public function render(array $data).
Response:
In my first solution I put the whole mainclass as parameter to the
render function. So this is a solution that will work in any case. But
if there is definitivly no relationship between these two objects I
prefer my second solution by setting the parameters directly with
$this->x_function->dummy = $dummy;
Sorry to tell you that you're wrong there. Implicitly setting a property on an object is in no way a defined interface. And I'm not using this word in the sense of PHP's interface keyword, I mean this in the broader sense of specifying how two pieces of code can interact and cooperate.
You've done a good job of specifying and using an interface for the render() function, this greatly decreases code coupling and increases flexibility and testability. Now you're destroying this again by using undefined and brittle property assignments.
You need to make the passing data into render aspect part of your interface specification. For example:
interface dummy_function {
public function render(array $data);
}
Or:
interface dummy_function {
public function setData(array $data);
public function render();
}
Or better:
interface DummyData {
/**
* #return string
*/
public function getDummyData();
}
interface DummyRenderer {
public function render(DummyData $data);
}
With this you're:
explicitly specifying what format your data is in (string)
codifying where render() can get access to such data (it'll receive a DummyData object which has a getDummyData() method)
You don't need to guess what property names are involved or what structure the passed object has.

Symfony2. How to ensure controller implements some method no matters if its public/private/protected and if it has any arguments?

I wonder if I can make controllers implementing some methods no matters if that method will be public, private or protected and if it will have any parameter. I just want to ensure, that controller has method with specified name, no more.
For example:
interface SomeInterface {
function someFunction();
function someOtherFunction();
}
class SomeController extends SomeBaseController implements SomeInterface {
//some action
public function someAction() { ... }
//an implementation of SomeInterface method
public function someFunction() { ... }
//an implementation of SomeInterface method
protected function someOtherFunction($someParameter) { ... }
}
I know that it's not possible to do this with ordinary php interfaces but maybe there is some other way in php or maybe symfony2 has some tool to accomplish this?
I know of one way to do this, which relies on the __call() method available in PHP: http://www.php.net/manual/en/language.oop5.overloading.php#object.call
__call() is triggered when invoking inaccessible methods in an object context.
You could go ahead and create a parent class that looks like this - although it's not an Interface, so take care if you need it outside a single domain.
class BaseClass{
public function __call($name, $arguments) {
$methodsToImplement = array(
'method1', 'method2', 'method3'
);
if (in_array($name, $methodsToImplement)) {
throw new Exception("Method " . $name . " is not yet implemented.");
}
}
}
It seems there is no way to accomplish this. So I mark my question as reslolved, however if someone knows an answer let me know! :)

Can I specify a non strict method requirement for child classes?

I have a base class in which I want to specify the methods a child class must have, but not implement them itself. However, the methods in a child class may have a different number of paramaters to the definition in the base class.
Having tried this with an abstract method, php doesn't allow this. Is it possible?
The child class's function can add extra, optional arguments to the signature without it causing errors:
abstract class Foo {
abstract function bar($a);
}
class NewFoo extends Foo {
function bar($a, $b = null) {
//do something
}
}
Short of specifying the abstract method with no parameters and requiring the subclassed method to access the args through func_get_args, I don't see how this would be possible.
I would say this is one of the weak points of PHP's object orientation, that it wasn't designed to handle this kind of use case. It just wasn't meant to allow overloaded methods for its
It is indeed possible to do what you're talking about as a kind of hack, in both the way mentioned above with:
func_get_args()
or, just (like the commenter mentioned) pass in an array of arguments. Alternately you could pass in an object that has your arguments as data members. Then you could extend the parameter/argument object for your child method.
The point is that PHP is a language that thrives on permissiveness and not restriction. Abstract classes have a very basic implementation in PHP. If you have the need for a lot of structure like this, then PHP really might not be the best language choice.
I don't think this is an answer that you will want to use in production as it will be fairly slow, but just for the sake of it I tried to write something using Reflection, which seems to work. You will still get an E_STRICT because method declarations in subclasses are apparently supposed to match.
class a {
protected $requiredMethodsInSubclass = array( 'method1', 'method2', 'method3' );
public function __construct() {
$reflObject = new ReflectionObject($this);
$className = $reflObject->getName();
if ($className == __CLASS__) {
//this class is being instanciated directly , so don't worry about any subclasses
return;
}
foreach ($this->requiredMethodsInSubclass as $methodName) {
try {
$reflMethod = $reflObject->getMethod($methodName);
} catch (ReflectionException $e) { //method not anywhere
trigger_error("Method $methodName is not declared in class " . __CLASS__ . " or subclass $className", E_USER_ERROR);
continue;
}
$declaringClass = $reflMethod->getDeclaringClass();
if ($declaringClass->getName() == __CLASS__) {
//method is declared in this class, not subclass
trigger_error("Method $methodName is not declared in subclass $className", E_USER_ERROR);
}
}
}
public function method1() {
}
public function method2($a) {
}
}
class b extends a {
public function __construct() {
parent::__construct();
//some stuff
}
public function method2($a, $b, $c) {
}
}
$b = new b();

Best practices to test protected methods with PHPUnit

I found the discussion on Do you test private method informative.
I have decided, that in some classes, I want to have protected methods, but test them.
Some of these methods are static and short. Because most of the public methods make use of them, I will probably be able to safely remove the tests later. But for starting with a TDD approach and avoid debugging, I really want to test them.
I thought of the following:
Method Object as adviced in an answer seems to be overkill for this.
Start with public methods and when code coverage is given by higher level tests, turn them protected and remove the tests.
Inherit a class with a testable interface making protected methods public
Which is best practice? Is there anything else?
It seems, that JUnit automatically changes protected methods to be public, but I did not have a deeper look at it. PHP does not allow this via reflection.
If you're using PHP5 (>= 5.3.2) with PHPUnit, you can test your private and protected methods by using reflection to set them to be public prior to running your tests:
protected static function getMethod($name) {
$class = new ReflectionClass('MyClass');
$method = $class->getMethod($name);
$method->setAccessible(true);
return $method;
}
public function testFoo() {
$foo = self::getMethod('foo');
$obj = new MyClass();
$foo->invokeArgs($obj, array(...));
...
}
teastburn has the right approach. Even simpler is to call the method directly and return the answer:
class PHPUnitUtil
{
public static function callMethod($obj, $name, array $args) {
$class = new \ReflectionClass($obj);
$method = $class->getMethod($name);
$method->setAccessible(true);
return $method->invokeArgs($obj, $args);
}
}
You can call this simply in your tests by:
$returnVal = PHPUnitUtil::callMethod(
$this->object,
'_nameOfProtectedMethod',
array($arg1, $arg2)
);
You seem to be aware already, but I'll just restate it anyway; It's a bad sign, if you need to test protected methods. The aim of a unit test, is to test the interface of a class, and protected methods are implementation details. That said, there are cases where it makes sense. If you use inheritance, you can see a superclass as providing an interface for the subclass. So here, you would have to test the protected method (But never a private one). The solution to this, is to create a subclass for testing purpose, and use this to expose the methods. Eg.:
class Foo {
protected function stuff() {
// secret stuff, you want to test
}
}
class SubFoo extends Foo {
public function exposedStuff() {
return $this->stuff();
}
}
Note that you can always replace inheritance with composition. When testing code, it's usually a lot easier to deal with code that uses this pattern, so you may want to consider that option.
I'd like to propose a slight variation to getMethod() defined in uckelman's answer.
This version changes getMethod() by removing hard-coded values and simplifying usage a little. I recommend adding it to your PHPUnitUtil class as in the example below or to your PHPUnit_Framework_TestCase-extending class (or, I suppose, globally to your PHPUnitUtil file).
Since MyClass is being instantiated anyways and ReflectionClass can take a string or an object...
class PHPUnitUtil {
/**
* Get a private or protected method for testing/documentation purposes.
* How to use for MyClass->foo():
* $cls = new MyClass();
* $foo = PHPUnitUtil::getPrivateMethod($cls, 'foo');
* $foo->invoke($cls, $...);
* #param object $obj The instantiated instance of your class
* #param string $name The name of your private/protected method
* #return ReflectionMethod The method you asked for
*/
public static function getPrivateMethod($obj, $name) {
$class = new ReflectionClass($obj);
$method = $class->getMethod($name);
$method->setAccessible(true);
return $method;
}
// ... some other functions
}
I also created an alias function getProtectedMethod() to be explicit what is expected, but that one's up to you.
I think troelskn is close. I would do this instead:
class ClassToTest
{
protected function testThisMethod()
{
// Implement stuff here
}
}
Then, implement something like this:
class TestClassToTest extends ClassToTest
{
public function testThisMethod()
{
return parent::testThisMethod();
}
}
You then run your tests against TestClassToTest.
It should be possible to automatically generate such extension classes by parsing the code. I wouldn't be surprised if PHPUnit already offers such a mechanism (though I haven't checked).
I'm going to throw my hat into the ring here:
I've used the __call hack with mixed degrees of success.
The alternative I came up with was to use the Visitor pattern:
1: generate a stdClass or custom class (to enforce type)
2: prime that with the required method and arguments
3: ensure that your SUT has an acceptVisitor method which will execute the method with the arguments specified in the visiting class
4: inject it into the class you wish to test
5: SUT injects the result of operation into the visitor
6: apply your test conditions to the Visitor's result attribute
You can indeed use __call() in a generic fashion to access protected methods. To be able to test this class
class Example {
protected function getMessage() {
return 'hello';
}
}
you create a subclass in ExampleTest.php:
class ExampleExposed extends Example {
public function __call($method, array $args = array()) {
if (!method_exists($this, $method))
throw new BadMethodCallException("method '$method' does not exist");
return call_user_func_array(array($this, $method), $args);
}
}
Note that the __call() method does not reference the class in any way so you can copy the above for each class with protected methods you want to test and just change the class declaration. You may be able to place this function in a common base class, but I haven't tried it.
Now the test case itself only differs in where you construct the object to be tested, swapping in ExampleExposed for Example.
class ExampleTest extends PHPUnit_Framework_TestCase {
function testGetMessage() {
$fixture = new ExampleExposed();
self::assertEquals('hello', $fixture->getMessage());
}
}
I believe PHP 5.3 allows you to use reflection to change the accessibility of methods directly, but I assume you'd have to do so for each method individually.
I suggest following workaround for "Henrik Paul"'s workaround/idea :)
You know names of private methods of your class. For example they are like _add(), _edit(), _delete() etc.
Hence when you want to test it from aspect of unit-testing, just call private methods by prefixing and/or suffixing some common word (for example _addPhpunit) so that when __call() method is called (since method _addPhpunit() doesn't exist) of owner class, you just put necessary code in __call() method to remove prefixed/suffixed word/s (Phpunit) and then to call that deduced private method from there. This is another good use of magic methods.
Try it out.
Alternative.The code below is provided as an example.
Its implementation can be much broader.
Its implementation that will help you test private methods and replacing a private property .
<?php
class Helper{
public static function sandbox(\Closure $call,$target,?string $slaveClass=null,...$args)
{
$slaveClass=!empty($slaveClass)?$slaveClass:(is_string($target)?$target:get_class($target));
$target=!is_string($target)?$target:null;
$call=$call->bindTo($target,$slaveClass);
return $call(...$args);
}
}
class A{
private $prop='bay';
public function get()
{
return $this->prop;
}
}
class B extends A{}
$b=new B;
$priv_prop=Helper::sandbox(function(...$args){
return $this->prop;
},$b,A::class);
var_dump($priv_prop);// bay
Helper::sandbox(function(...$args){
$this->prop=$args[0];
},$b,A::class,'hello');
var_dump($b->get());// hello
You can use Closure as in the code below
<?php
class A
{
private string $value = 'Kolobol';
private string $otherPrivateValue = 'I\'m very private, like a some kind of password!';
public function setValue(string $value): void
{
$this->value = $value;
}
private function getValue(): string
{
return $this->value . ': ' . $this->getVeryPrivate();
}
private function getVeryPrivate()
{
return $this->otherPrivateValue;
}
}
$getPrivateProperty = function &(string $propName) {
return $this->$propName;
};
$getPrivateMethod = function (string $methodName) {
return Closure::fromCallable([$this, $methodName]);
};
$objA = new A;
$getPrivateProperty = Closure::bind($getPrivateProperty, $objA, $objA);
$getPrivateMethod = Closure::bind($getPrivateMethod, $objA, $objA);
$privateByLink = &$getPrivateProperty('value');
$privateMethod = $getPrivateMethod('getValue');
echo $privateByLink, PHP_EOL; // Kolobok
$objA->setValue('Zmey-Gorynich');
echo $privateByLink, PHP_EOL; // Zmey-Gorynich
$privateByLink = 'Alyonushka';
echo $privateMethod(); // Alyonushka: I'm very private, like a some kind of password!
I made a class for invoking easily private methods (static and non-static) for unit-testing purposes:
class MethodInvoker
{
public function invoke($object, string $methodName, array $args=[]) {
$privateMethod = $this->getMethod(get_class($object), $methodName);
return $privateMethod->invokeArgs($object, $args);
}
private function getMethod(string $className, string $methodName) {
$class = new \ReflectionClass($className);
$method = $class->getMethod($methodName);
$method->setAccessible(true);
return $method;
}
}
Example of usage:
class TestClass {
private function privateMethod(string $txt) {
print_r('invoked privateMethod: ' . $txt);
}
}
(new MethodInvoker)->invoke(new TestClass, 'privateMethod', ['argument_1']);

Categories