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"?)
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 operates 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 Male extends Person {
public static function whatAmI() {return "Male";}
}
$p = new Male;
$p->saySelf(); // returns "I am Human"
$p->sayThis(); // returns "I am Male"
$p->sayStatic(); // returns "I am Male"
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.
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
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().
Related
What is the correct way of setting a type for mocked objects?
Example code:
/**
* #dataProvider getTestDataProvider
* #throws Exception
*/
public function testExampleData(
Request $request,
Response $expected,
SomeClass $someClassMock
): void {
$result = $someClassMock->getData($request);
$this->assertEquals($expected, $result);
}
In this example the type of $someClassMock is class SomeClass. Also there is a type called MockObject which is also working properly, but it messes up the autocompletion of functions inside that class.
Which types should I use on these mocked objects? Real object class or MockObject?
What I do to make sure the auto completion works for the mocked class as well as the MockObject, is tell php that it can be either class. This adds the auto complete for both and also makes it quite understandable for anyone reading the code that it is a mock and what object it is mocking.
In your case it would look like this:
/**
* #dataProvider getTestDataProvider
* #throws Exception
*/
public function testExampleData(
Request $request,
Response $expected,
SomeClass|MockObject $someClassMock // <-- Change made here
): void {
$result = $someClassMock->getData($request);
$this->assertEquals($expected, $result);
}
You will still be passing in the MockObject, but your IDE will not complain about any unknown functions.
EDIT: To make it work with PHP versions before 8, I would suggest something like this (minimal example):
class ExampleTest extends TestCase
{
private someClass | MockObject $someClassMock;
public function setUp(): void
{
$this->someClassMock = $this->createMock(SomeClass::Class);
}
public function testMe()
{
$this->someClassMock->expects($this->once())->method('getData')->willReturn('someStuff');
}
}
In this scenario the variable $someClassMock is declared as both types and you can use it throughout your test with autocompletion for both of them. This should also work with your data provider although you might have to rewrite it slightly. I didn't include it in my example to keep it simple.
In my PHP application I have a base class for all database objects, which is further extended by specific model classes. It goes on like this (simplified):
abstract class Model extends Collection {
(...)
function __construct(string $primary_key, string $value) {
$data = MysqlDB::instance() -> select(static::TABLE, implode(',', static::COLUMNS), "$primary_key=\"$value\"");
if (count($data) != 1)
throw new ModelException('Select condition uncertain');
parent::__construct($data[0]);
}
public static function getById(string $id) : ?Model {
try {
return new static('id', $id);
} catch (ModelException $e) {
return NULL;
}
}
(...)
}
The point is, I use the getById function on child classes to obtain the needed objects. However, since the return type of getById method is Model, PhpStorm can't figure out what methods the objects has and highlights the ones I use as an error. Consequently, no type-hinting available.
For instance, assuming that final class User extends Model and that class User has method sendNotification, this kind of code:
User::getById($id) -> sendNotification($param1, $param2, ...)
has sendNotification yellowed out as though it did not exist.
I know this isn't that much of an issue, but it's really irritating in terms of that I get distracted by constant redundant warnings and that I can't use type-hinting in such a usage case.
Try with actual PHPDoc for your getById() where you specify dynamic type (e.g. #return static or #return $this).
That's the most common way of providing such "this class and its' children" typehint.
Another possible option is kind of the same .. but using PHP 7.1 functionality (so no PHPDoc blocks).
Try using self as return type instead of Model. I mean here:
public static function getById(string $id) : ?Model {
use this instead:
public static function getById(string $id) : ?self {
But for this one you should use PhpStorm 2017.2 EAP build as 2017.1.x has issues with that (see https://stackoverflow.com/a/44806801/783119 as an example).
There are three ways to achieve this, none of them has anything to do with PHPStorm.
First overwrite the method in every child with the proper return type:
/**
* #return User
*/
public static function getById(string $id) : ?Model { return parent::getById($id); }
Second add all possible children to the return tag of the abstract class.
/**
* #return Model|User|...
*/
public static function getById(string $id) : ?Model { /* ... */ }
Third add a type hint just in place:
/** #var User $user */
$user = User::getById($id);
$user->sendNotification($param1, $param2, ...);
These are not nice and hard to maintain. But there is no "setting" in PHPStorm for that.
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"?)
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 operates 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 Male extends Person {
public static function whatAmI() {return "Male";}
}
$p = new Male;
$p->saySelf(); // returns "I am Human"
$p->sayThis(); // returns "I am Male"
$p->sayStatic(); // returns "I am Male"
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.
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
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().
* Sorry, I am learning English now and my English is still not so good. Please understand my situation.
As far as I know, Static is required to use like Class::Function(params);
Like this one.
class Foo {
static function Bar($msg){
echo $msg;
}
}
There is one file in XE(is CMS developed in Korea).
(XE Official Site : http://www.xpressengine.com/?l=en)
Of course, This is a summary of real file
<?php
/**
* Manages Context such as request arguments/environment variables
* It has dual method structure, easy-to use methods which can be called as self::methodname(),and methods called with static object.
*/
class Context
{
/**
* codes after <body>
* #var string
*/
public $body_header = NULL;
/**
* returns static context object (Singleton). It's to use Context without declaration of an object
*
* #return object Instance
*/
function &getInstance()
{
static $theInstance = null;
if(!$theInstance)
{
$theInstance = new Context();
}
return $theInstance;
}
/**
* Add html code after <body>
*
* #param string $header Add html code after <body>
*/
function addBodyHeader($header)
{
is_a($this, 'Context') ? $self = $this : $self = self::getInstance();
$self->body_header .= "\n" . $header;
}
}
This is the comment at the top of this file.
It has dual method structure, easy-to use methods which can be called
as self::methodname(),and methods called with static object.
In this comment, It can use Class::Function() and I have been using in XE.
But it don't tell how they make. How can I make like it?
Edit1 :
The file's name is Context.class.php and It is included in other files.
<?php
require(_XE_PATH_ . 'classes/context/Context.class.php');
Context::addBodyHeader("Some Codes");
?>
In this comment, It can use Class::Function() and I have been using in
XE. But it don't tell how they make. How can I make like it?
The :: is called the scope resolution operator.
They make it as follows:
class MyClass {
public static function saySomething() {
echo 'hello';
}
public function sayHello() {
echo 'hello';
}
public function helloSay() {
self::sayHello();
}
}
MyClass::saySomething();
MyClass::sayHello();
MyClass::helloSay();
They all output: hello
Well in this case they use self, which doesn't need the static, you can compare self:: to $this->, just that self:: also works for static functions.
Maybe the manual helps you
Not sure if this is what you are trying to do, but you can declare "static" in php public static function methodName() and then call the function with Class::Method() You can also check out this for more data on static.
EDIT:
This is from php.net:
The pseudo-variable $this is available when a method is called from
within an object context. $this is a reference to the calling object
(usually the object to which the method belongs, but possibly another
object, if the method is called statically from the context of a
secondary object).
So basically you can do this (call class method static way).
I'm working on a class which needs to be accessible via static function calls as well as object methods. One thing I have found is that I'm duplicating logic across multiple functions.
Simplified example:
class Configurable{
protected $configurations = array();
protected static $static_configurations = array();
public function configure($name, $value){
// ...lots of validation logic...
$this->configurations[$name] = $value;
}
public static function static_configure($name, $value){
// ...lots of validation logic (repeated)...
self::$static_configurations[$name] = $value;
}
}
I've found a solution to this, but it feels really dirty:
class Configurable{
protected $configurations = array();
protected static $static_configurations = array();
public function configure($name, $value){
// ...lots of validation logic...
if (isset($this)){
$this->configurations[$name] = $value;
}
else{
self::$static_configurations[$name] = $value;
}
}
}
I need the static function as well so that I can set configurations throughout the application. Also, the nice thing with this technique is that I can use the same method names in both scopes.
Are there any problems with testing scope like this? Performance issues, forward compatibility issues, etc. It all works for me on PHP 5.2, and I don't need to support <5.
The issue with the second method is that it will result in an error when error reporting is set to E_STRICT. For example:
Strict standards: Non-static method Foo::bar() should not be called statically in /home/yacoby/dev/php/test.php on line 10
A point with PHP6 is that the E_STRICT errors are moved to E_ALL. In other words E_ALL will cover all errors including not allowing you to call non static methods statically.
An alternative method may be to move the validation logic to a static function. That way the non static function and the static function can call the validation logic.
Static methods would require a different number of arguments than their objective counterpart - the additional argument would be an execution context. If there's no execution context, then it only makes sense to call it statically.
My preferred approach given that I'm building a library with multiple interfaces like this, is to create a static class and a dynamic class. Have one proxy the calls to the other. For example:
class DynamicClass {
protected $foo;
protected $bar;
public function baz($arg1) {
return StaticClass::bar($this->foo, $arg1);
}
public function zop($arg1, $arg2) {
return StaticClass::zop($this->foo, $this->bar, $arg1, $arg2);
}
// Context-less helper function
public function womp($arg1) {
return StaticClass::womp($arg1);
}
}
class StaticClass {
public static function baz(&$fooContext, $arg1) { ... }
public static function zop(&$fooContext, &$barContext, $arg1, $arg2) { ... }
public static function womp($arg1) { ... }
}
It's up to you exactly how you pass context to the static class - you'll have to do whatever makes sense for you. The work done in most functions should be pretty minor (if you're doing a lot, then you probably should be breaking the work up into smaller functions as a rule), and so should only require a handful of context arguments. Or you could create a full context array and pass that around everywhere (either populating it in DynamicClass just before each call, or else track all DynamicClass properties in that array so you can quickly & easily pass it around.
Though actually it looks like you might benefit from a Singleton design pattern. From what I can see, you're trying to create a global Configurable, and also have the option to create individual local Configurables. With the singleton design pattern, you create a globally accessible version of a class that you can guarantee you only have one of (without breaking OOP design principles and having to rely on $_GLOBALS etc). For example:
class DynamicClass {
protected $foo;
protected $bar;
public function baz($arg1) { ... }
public function zop($arg1, $arg2) { ... }
public static function getSingleton() {
static $instance = null;
if ($instance === null) $instance = new DynamicClass();
return $instance;
}
}
No matter where in your code you are, you can get access to the same instance with DynamicClass::getSingleton(). You also have the option of creating one-off non-singleton versions. You essentially get the best of both worlds while only having to write all your methods with dynamic access in mind exclusively.
I don't find it so absurd to allow calling a method on an instance and statically as well. My case:
TestRecord::generateForm(); // Generate an empty form.
$test = new TestRecord( $primaryKey );
[...]
$test->generateForm(); // Generate an edit form with actual $test values.
Static side of my class deals with blank/new logics,
while instance side means live data are used.
PHP 5.3 allows to achieve this by using __call, __callStatic and static:: :
public function __call( $name, $args )
{
if ( $name == 'generateForm' ) {
$this->fields = static::createFields(); // Action 1 : static.
$this->fillFields(); // Action 2 : instance.
static::renderForm( $this->fields ); // Action 3 : static.
}
}
public static function __callStatic( $name, $args )
{
if ( $name == 'generateForm' ) {
$fields = static::createFields(); // Action 1 : static.
// Action 2 : none.
static::renderForm( $fields ); // Action 3 : static.
}
}
Note: The static:: late binding qualifier is used because my 3 action methods (createFields, fillFields and rendreForm) are implemented as protected in the subclasses of this one, which is abstract. This is possible because PHP let protected members be accessed in both directions: from base to subclass, but from subclass to superclass as well. Which is different from other OO languages, as far as I know.
as in core php we use index.php?var=, so to do the same thing in oop php what should we use.