PHPUnit - Use $this or self for static methods?
Asked Answered
K

3

36

I don't want to write a long text, because it is a short question. PHPUnit tests contain several methods that are static. For example all those \PHPUnit\Framework\Assert::assert*() methods and also the identicalTo, equalTo.

My IDE (with IntelliSense/autocompletion) doesn't accept calls with $this, but with self. I have learned that static functions should be called through the class, not an object, so self.

What is more correct?

$this->assertTrue('test');

or

self::assertTrue('test');

?

(And if "$this" is more correct, can you maybe point out why we should not use "self"?)

Kilgore answered 4/5, 2015 at 22:47 Comment(1)
This is a good question. I also don't fully understand why methods are static, but all code I saw use $this instead of self.Ictus
S
13

Generally, self is only used to refer to static methods and properties (though confusingly you can refer to non-static methods with self, and to static methods with $this, provided the methods called with self don't reference $this.)

<?php
class Test {
    public static function staticFunc() {echo "static ";}
    public function nonStaticFunc() {echo "non-static\n";}
    public function selfCaller() {self::staticFunc(); self::nonStaticFunc();}
    public function thisCaller() {$this->staticFunc(); $this->nonStaticFunc();}
}
$t = new Test;
$t->selfCaller();  // returns "static non-static"
$t->thisCaller();  // also returns "static non-static"

Inheritance is important to remember when dealing with $this or self. $this will always refer to the current object, while self refers to the class in which self was used. Modern PHP also includes late static binding via the static keyword, which will operate the same way as (and should be preferred over) $this for static functions.

<?php
class Person {
    public static function whatAmI() {return "Human";}    
    public function saySelf() {printf("I am %s\n", self::whatAmI());}
    public function sayThis() {printf("I am %s\n", $this->whatAmI());}
    public function sayStatic() {printf("I am %s\n", static::whatAmI());}
}

class Programmer extends Person {
    public static function whatAmI() {return "a programmer";}
}

$p = new Programmer;
$p->saySelf();    // returns "I am Human"
$p->sayThis();    // returns "I am a programmer"
$p->sayStatic();  // returns "I am a programmer"

As regards PHPUnit in particular, it appears they simply do things the way they've always done them! Though according to their documentation, your code should work fine using static methods.

Stingo answered 17/3, 2017 at 22:38 Comment(3)
That's a really good answer. Sorry I've seen it that late. Now I am understanding more how those identifiers work. But still, the concept is confusing to me. Why can you overwrite static functions in PHP so that the return value actually changes in childs? And besides why that is possible, why is PHPUnit using $this-> and not the correct static:: access then? Legacy code?Kilgore
"Static" doesn't mean it's unchanging, as in regular English usage. It simply describes how it's called (i.e. without needing an instance of an object) so there's no problem redefining them in child classes. I'm not familiar with PHPUnit, but it looks like it's just the way they do things.Stingo
I still can't wrap my head around how dirty and confusing that is, but I guess that's simply how PHP is. Thanks for your quick reply, I guess your answer combined with the link you gave here should be enough information for future readers. I'll mark this as solved.Kilgore
R
3

The phpunit documentation says you can use either and doesnt advocate one over the other. So you choose! https://phpunit.readthedocs.io/en/9.2/assertions.html

Ranchman answered 3/8, 2020 at 8:34 Comment(1)
That's basically just the last sentence of my answer from 3 years previous but okStingo
S
2

PHPUnit 4.8.9: vendor/phpunit/phpunit/src/Framework/Assert.php:

/**
 * Asserts that a condition is true.
 *
 * @param bool   $condition
 * @param string $message
 *
 * @throws PHPUnit_Framework_AssertionFailedError
 */
public static function assertTrue($condition, $message = '')
{
    self::assertThat($condition, self::isTrue(), $message);
}

Technically static::assertTrue() is correct, but the common usage of the assert methods is $this->assertTrue().

Sallet answered 19/10, 2015 at 10:7 Comment(1)
But why do you should use $this->assertTrue(), if self::assertTrue() would be the more correct way? I do not understand the point in this. That was the reason for my question.Kilgore

© 2022 - 2024 — McMap. All rights reserved.