// in class
public function test () {
$this->__invoke();
}
$inst->test();
This test runs without any error.
My question: is there some reason why this should not be done? Are there any corner cases, hidden caveats, or does it behave like any regular function/method?
That should not work since there is no __invoke() method in your class:
class SomeClass {
public function test()
{
$this->__invoke();
}
}
$inst = new SomeClass();
$inst->test();
http://3v4l.org/JOBXn.
If you implement __invoke(), that should work:
class SomeClass {
public function __invoke()
{
var_dump('Invoke!');
}
}
$inst = new SomeClass();
$inst();
http://3v4l.org/mpG5d.
Magic methods can be called directly as you can see in the second test, but in my opinion it is not a good idea since they are some kind of hooks and their code could be executed unexpectedly.
Related
I know that creating an instance of a Class in the middle of a method it's a bad practice since it makes code hard to test.
But I can't refactor the code, so I need to find a way to mock an Object created with new in the middle of a method under test.
Used Frameworks: PHPUnit, Mockery, WP_Mock
Example: Here I need to mock the get_second_string() method from the instance of the class ExternalClass
Class MyClass {
function methodUnderTest($string) {
$objToMock = new ExternalClass();
$second_string = $objToMock->get_second_string();
$final_string = $string . $second_string;
return $final_string;
}
}
Class TestMyClass extends PHPUnit_Framework_TestCase {
public function setUp() {
}
public function tearDown() {
}
public function test_methodUnderTest() {
$externalObject = $this->getMockBuilder('ExternalClass')
->setMethods(['get_second_string'])
->getMock;
$externalObject->expects($this->once())
->method('get_second_string')
->willReturn(' two');
$testObj = new MyClass();
$this->assertEquals('one two', $testObj->methodUnderTest('one');
}
}
If you really have no opportunity to refactor the code or do some appropriate integration testing, you might want to take a look at https://github.com/php-test-helpers/php-test-helpers#intercepting-object-creation and https://github.com/krakjoe/uopz/tree/PHP5
Still I think the code you make would profit a lot more from refactoring than monkey patching.
Besides, the refactoring does not need to be very heavy. You might do at least this:
class MyClass
{
private $externalsFactory;
public function __construct($externalsFactory){
$this->externalsFactory = $externalsFactory;
}
public function methodUnderTest($str){
$external = $this->externalsFactory->make();
$second_string = $external->get_second_string();
$finalString = $str.$second_string;
return $finalString;
}
}
class ExternalsFactory
{
public function make(){
return new ExternalClass();
}
}
class ExternalClass
{
public function get_second_string(){
return 'some real stuff may be even from database or whatever else it could be';
}
}
class MyClassTest extends PHPUnit_Framework_TestCase
{
private $factoryMock;
private $myClass;
public function setUp(){
$this->factoryMock = $this->getMockBuilder('ExternalsFactory')
->getMock();
$this->myClass = new MyClass($this->factoryMock);
}
public function testMethodUnderTest(){
$extenalMock = $this->createMock('ExternalClass');
$extenalMock->method('get_second_string')
->willReturn('second');
$this->factoryMock->method('make')
->willReturn($extenalMock);
$this->assertSame('first-and-second', $this->myClass->methodUnderTest('first-and-'));
}
}
IMHO there is no way to do such a thing. You should pass the object as parameter to the method.
You can not mock entire object.
But with phpunit you can do something like this:
$f = $this->getMockBuilder(<your_class>)->disableOriginalConstructor()
->setMethods(array(
<mocked_method_1>, <mocked_method_2>
))->getMock();
This way, newly created object ommits constructor and you specify which method are going to behave normally and which you mock.
in testing you can specify what the method/s will return, like this:
$f->method(<mocked_method_1>)->willReturn(<dummy_data>);
using this, you will not test the mocked object in any way, but can test method which is creating the object..
I was trying to figure out if I can instantiate a class within its own constructor and I came across this:
Why Can You Instantiate a Class within its Definition?.
Then I tried the same thing in PHP:
Class someClass {
function __construct() {
$objNew = new someClass();
$objNew->doit();
}
function doit() {
echo "Do it man!\n";
}
}
$oNew = new someClass();
Everytime I tried to run this I got a "Segmentation Fault" error.....
With reference to the above code and even the link posted above, I want to think that instantiating a class within its own constructor would cause an infinite number of objects to get created (until the server crashes, of course!).....any thoughts on what is going on above? Why is it ok to do this in Java and (perhaps) not in PHP?
It's not the same thing. On the question Why Can You Instantiate a Class within its Definition?, a static method is used to instantiate his class. Static methods are stored with the class definition (like a blueprint) inside the heap memory and do not require to be instantiated.
You could create a static method, and this one will have to create a new instance of your class:
Class someClass {
function __construct() {
$this->doit();
}
static function createSomeClass() {
return new someClass();
}
function doit() {
echo "Do it man!\n";
}
}
$oNew = someClass::createSomeClass();
Php is not compiled but interpreted. Java is compiled and after this executed. So the class itself is not yet all defined and you call it again in php so this throws an error.
Below is the right solution for you
<?php
Class someClass {
function __construct() {
$this->doit();
}
function doit() {
echo "Do it man!\n";
}
}
$oNew = new someClass();
?>
If all you want to do is call that method when object is instantiated. Then, there's no meaning of doing this $objNew = new someClass();. Its useless. Simply, do this:
class someClass {
function __construct() {
$this->doit();
}
function doit() {
echo "Do it man!\n";
}
}
$oNew = new someClass();
I'm trying to test a static method on a class, but it relies on a static array property that doesn't get reset between tests, so I though I could create a mock class & test against that.
The only problem is that the mock class static method is not returning the value as the original static method does.
Here's my class...
class Thing {
static public function doThing() {
return 'yeah!';
}
}
... and here's be test class...
class ThingTest {
public function testDoSomething() {
$mock_class = $this->getMockClass('Thing');
$this->assertEqual('yeah!', $mock_class::doThing())
}
}
This test fails with the message "Failed asserting that null matches expected 'yeah!'."
What am I missing here? I thought not specifying the methods on the getMock() call meant that the original methods carried over, but clearly not. :o(
Any pointers would be great. Thanks.
Edit
I typed this up from memory, rather than from copying code, as I'd made further change to try to resolve this. After writing more tests for mock objects I realised that if you pass array() as the second parameter ($methods) to getMock[Class] then it stubbed out all the methods, & I believe this is what I had actually done. I was doing this, as I also wanted to pass the constructor parameter in the 3rd argument. The code probably looked more like this...
class ThingTest {
public function testDoSomething() {
$mock_class = $this->getMockClass(
'Thing',
array(),
array( 'something' )
);
$this->assertEqual('yeah!', $mock_class::doThing())
}
}
Maybe $mock_class is an object, not a string class name? Try to use next:
class ThingTest {
public function testDoSomething() {
$mock_class = $this->getMockClass('Thing');
$this->assertEqual('yeah!', Thing::doThing())
}
}
Is this work?
You forgot extending by PHPUnit_Framework_TestCase.
class ThingTest extends PHPUnit_Framework_TestCase {
public function testDoSomething() {
$mock_class = $this->getMockClass('Thing');
$this->assertEqual('yeah!', $mock_class::doThing())
}
}
You shouldn't mock the class containing the method you want to test. If you mock the class, you can't call any method either before you haven't defined it via
-> expects('methodName')
-> with($this->equalTo($parameter),[$this->equalTo($parameter2),...])
-> will($this->returnValue($value))
. Mocking is used to reduce complexity of a test. Let's say you want to test a function that looks like this:
class test{
private $someClass;
public function __construct(SomeInterface $someClass){
$this -> someClass = $someClass;
}
public function test(){
$someVariable = $this -> someClass -> doSomething();
changeSomething($someVariable);
return $someVariable;
}
}
If you don't mock someClass, you'd have to test the whole code of someClass -> doSomething. But that is not what you want to do. You just want to use the return of the function doSomething. That is the point where you need a mock. It reduces the complexity of your test and offers REAL UNIT tests instead of testing the whole app.
So what you need to do is:
class ThingTest {
public function testDoSomething() {
$class = new Thing();
$this->assertEquals('yeah!', $class::doThing());
}
}
There is no need for a mock.
I'm not really sure if what I am looking for has a name, so it has been a bit difficult for me to search for, so I apologise if what I am asking has already been answered here before.
The situation is that I have an abstract class which has, of course, many other classes which extend it.
The abstract method in the abstract class is called run() and all of the extending classes define this method.
My problem is that I want to call some common code after the run() method has been called, but I want to know if there is a better way to do this.
I could of course just paste my common code into each and every extending class's run() method, but if I do that then it would be a lot of work for me to make simple changes from that point onward.
I could also put my common code into a method in the parent class and then call if from the extending class's run() method with $this.
But my question is, is there a better way to do this, or do I have to either use the $this keyword or paste in the code into each class's?
Here is a small example of what I want to do with my current idea:
abstract class Parent_Class {
public abstract function run();
protected function common_code() {
// Common code here
}
}
class Child_Class {
public function run() {
// Code here
// I want some common code to run after the run method has been called
$this->common_code(); // Is this the best way to do it?
}
}
Or is it possible to somehow tell the class that when the run() method has been called to automatically run the common_code() method?
A far simpler way to do this would to simply have a third method which calls run() and then calls common_code(). Subclasses can then override run() all they want.
abstract class Parent_Class {
public abstract function run();
protected function common_code() {
// Common code here
}
protected function start() {
$this->run();
$this->common_code();
}
}
class Child_Class {
public function run() {
// Code here
}
}
Based on Bradley Forster answer, you can define the method as protected, so when it's called from outside the class, you can intercept the event with php magic __call metod because
__call() is triggered when invoking inaccessible methods in an object context.
and then you can execute that method from the __call function
class A {
public function __call($method, $args){
if(!method_exists($this, $method))
throw new Exception("Call to undefined method ".__CLASS__."::$method()");
echo "doing something BEFORE function 'run' execution\n";
$retval = call_user_func_array(array($this, $method), $args);
echo "doing something AFTER function 'run' execution\n";
return $retval;
}
protected function run() {
echo "function 'run' executed\n" ;
}
}
$a = new A;
$a->run();
The answer given by Amber is nice and simple. But requires you to put your data in run() but call start(). Here is an alternative that allows you to have your code $a->run() in all your scripts, and $a->run() with your common code, but encapsulated in a namespace.
File hooks.php
<?php
// File: hooks.php
namespace hook;
class processHooks {
public function __construct() { /* Fatal Error without constructor */ }
protected function processHooks($_c, $method, $args) {
/* Swap the next two callbacks to run your custom code after */
call_user_func_array("\hook\\{$_c}::{$method}", $args);
return call_user_func_array(array($_c,$method), $args);
}
}
class A {
public function foo() {
echo 'Doing code stuff BEFORE calling child function....<br>';
}
}
File regular_file.php
<?php
// File: regular_file.php
include "hooks.php";
class A extends \hook\processHooks {
/* All that is required is this function
* and the function with common code to be protected
*/
public function __call($method, $args) {
self::processHooks(__CLASS__, $method, $args);
}
protected function foo() {
echo 'Method is called....<br>';
}
}
$a = new A();
$a->foo();
This works beacause method foo of class A in regular_file.php is protected, so it's not callable outside the class, so calling it triggers PHP magic method __call
__call() is triggered when invoking inaccessible methods in an object context.
how do i call a static method from another method inside the same class?
$this->staticMethod();
or
$this::staticMethod();
self::staticMethod();
More information about the Static keyword.
Let's assume this is your class:
class Test
{
private $baz = 1;
public function foo() { ... }
public function bar()
{
printf("baz = %d\n", $this->baz);
}
public static function staticMethod() { echo "static method\n"; }
}
From within the foo() method, let's look at the different options:
$this->staticMethod();
So that calls staticMethod() as an instance method, right? It does not. This is because the method is declared as public static the interpreter will call it as a static method, so it will work as expected. It could be argued that doing so makes it less obvious from the code that a static method call is taking place.
$this::staticMethod();
Since PHP 5.3 you can use $var::method() to mean <class-of-$var>::; this is quite convenient, though the above use-case is still quite unconventional. So that brings us to the most common way of calling a static method:
self::staticMethod();
Now, before you start thinking that the :: is the static call operator, let me give you another example:
self::bar();
This will print baz = 1, which means that $this->bar() and self::bar() do exactly the same thing; that's because :: is just a scope resolution operator. It's there to make parent::, self:: and static:: work and give you access to static variables; how a method is called depends on its signature and how the caller was called.
To see all of this in action, see this 3v4l.org output.
This is a very late response, but adds some detail on the previous answers
When it comes to calling static methods in PHP from another static method on the same class, it is important to differentiate between self and the class name.
Take for instance this code:
class static_test_class {
public static function test() {
echo "Original class\n";
}
public static function run($use_self) {
if($use_self) {
self::test();
} else {
$class = get_called_class();
$class::test();
}
}
}
class extended_static_test_class extends static_test_class {
public static function test() {
echo "Extended class\n";
}
}
extended_static_test_class::run(true);
extended_static_test_class::run(false);
The output of this code is:
Original class
Extended class
This is because self refers to the class the code is in, rather than the class of the code it is being called from.
If you want to use a method defined on a class which inherits the original class, you need to use something like:
$class = get_called_class();
$class::function_name();
In the later PHP version self::staticMethod(); also will not work. It will throw the strict standard error.
In this case, we can create object of same class and call by object
here is the example
class Foo {
public function fun1() {
echo 'non-static';
}
public static function fun2() {
echo (new self)->fun1();
}
}
call a static method inside a class
className::staticFunctionName
example
ClassName::staticMethod();