PHPUnit: setUpBeforeClass and tearDownAfterClass is not working - php

In my test cases, I have extend my test case class to another base class, where I have used setUp to set the global variables. I have extended this base class to child class where I have written test cases. Now, I have many child test classes which extends this base class. That's why, rather than using setUp in each child class, I have used only in base class.
This is my setup:
Base Class
use PHPUnit\Framework\TestCase;
class BaseClass extends TestCase
{
public static function setUpBeforeClass(){
//global vars setup
}
public static function tearDownAfterClass(){
//global vars teardown
}
}
Child Class
class ChildClass extends BaseClass
{
public static function setUpBeforeClass(){
//setup some other stuff related to only this child class
parent::setUpBeforeClass();
}
public static function tearDownAfterClass(){
//teardown some other stuff related to only this child class
parent::tearDownAfterClass();
}
}
Now, I want to use PHPUnit's setUpBeforeClass and tearDownAfterClass in my child classes to do some other stuff which is only related to only this child class.
But it is not working. After running tests, PHPUnit stops suddenly without throwing any errors. Kindly guide me here.

Related

get_class_vars() in an abstract class returns wrong variables

I coded a bunch of classes extending an abstract class in PHP. The abstract class has variables as well as the class which extends the abstract class.
I would like to create a method inside the abstract class, which return all the class variables of the child classes but don't have to be recoded in every subclass.
This snippet works fine in a subclass in order to get all variables, the ones from the abstract class and the other classes:
get_class_vars(get_class($this))
However, if I move this snippet to the abstract class, it doesnt work. Here's what I did:
public function test($test)
{
var_dump(get_class($test));
var_dump(get_class_vars(get_class($test)));
}
This code returns the class name of the passed class correctly, but the get_class_vars() does only return the variables of the abstract class, no matter which class is passed here.
What did I do wrong here?
<?php
abstract class Entity
{
protected int $top;
public function test()
{
var_dump(get_called_class());
var_dump(get_class_vars(get_called_class()));
}
}
class Sub extends Entity
{
public String $test; // CHANGED FROM PRIVATE TO PUBLIC!
}
$test = new Sub();
$test->test();
I found the solution - it was a "private" issue. The variable in the subclass needs to be at least a protected variable in order to be seen from the top class.

PHP OOP class construct inheritance

I am trying to understand one PHP OOP concept, lets say i have two classes A and B. B extends A there fore A is Base/Parent class. If class A has a __construct class B will automatically inherit it...?
Example:
class Car
{
public $model;
public $price;
public function __construct()
{
$this->model = 'BMW';
$this->price = '29,00,00';
}
}
class Engine extends Car
{
parent::__construct();
}
By parent::__construct(); class Engine will execute Car __construct(); automatically?
But I always though if I inherit from parent class the __construct will be executed automatically anyway why would I add this parent::__construct()?
When one class extends another, it inherits all its methods. Yes, that includes the constructor. You can simply do class Engine extends Car {}, and Engine will have a constructor and all other properties and methods defined in Car (unless they're private, which we'll ignore here).
If you define a method of the same name as already exists in Car in Engine, you're overriding that method implementation. That's exactly what it sounds like: instead of Car's implementation, Engine's method is called.
why would I add this parent::__construct()?
If you're overriding a method, yet you also want to call the parent's implementation. E.g.:
class Engine extends Car {
public function __construct() {
parent::__construct();
echo 'Something extra';
}
}
Overriding a constructor in a child class is exactly that, overriding... you're setting a new constructor for the child to replace the parent constructor because you want it to do something different, and generally you won't want it to call the parent constructor as well..... that's why you need to explicitly call the parent constructor from the child constructor if you want them both to be executed.
If you don't create a child constructor, then you're not overriding the parent constructor, so the parent constructor will then be executed

Configuration and inheritance chains in PHP

I have a few standard classes:
abstract class Parent {}
class Child1 extends Parent {}
class Child2 extends Parent {}
The Parent class contains logic common to both child classes, but each child class has its own additional logic.
For each of my clients, this logic can be configurable. So for any particular client, I may have:
abstract class ClientParent {}
class ClientChild1 extends ClientParent {}
class ClientChild2 extends ClientParent {}
The problem I'm having is how to get the logic from the standard classes into these ones. The first approach would be something like this:
abstract class ClientParent extends Parent {}
Okay, now I have the standard parent logic in all my client-specific classes. Great. But the child classes are already extending ClientParent, so we can't do the same thing for them. My "solution" is then to do this:
abstract class Parent {}
class Child1 extends ClientParent {}
class Child2 extends ClientParent {}
abstract class ClientParent extends Parent {}
class ClientChild1 extends Child1 {}
class ClientChild2 extends Child2 {}
There; now all the appropriate logic is passed down and everybody's happy. Except that now my standard classes are coupled to a particular client. As I have many clients, this is obviously no good.
What's my out here? Is there a way to address this through inheritance alone, or should I look into more complex configuration injection strategies?
Edit:
I'm using PHP 5.3, so I am unable to use traits to solve this problem.
PHP does not support multiple inheritance which is what I think you are trying to approximate here. It does however support (as of 5.4) traits, which in many cases can provide you with comparable functionality.
trait ParentTrait {
public function someUsefulMethod(){/*...*/};
public function someOtherUsefulMethod(){/*...*/};
}
abstract class ClientParent(){}
class ClientChild1 extends ClientParent {
use ParentTrait;
}
$clientChild1 = new ClientChild1();
$clientChild1->someUsefulMethod();
Another option would be to use composition instead, possibly for your problem employing the Strategy pattern would work.
class SuperWidget extends Widget{
private $dataStrategy;
public function __construct(DataStrategy $strategy){
$this->dataStrategy = $strategy;
}
// do this if you need to expose the functionality.
public function getData(){
return $this->dataStrategy->getData();
}
// or if you are just using it in your class
public function renderWidget($option){
$data = $this->dataStrategy->getData($option);
// use the data to render the widget;
return $renderedWidget;
}
}
$dataStrategy = JsonDataStrategy("http://data.source.url/jsonService.php");
$widget = new SuperWidget($dataStrategy);

PHP - Object instantiation context - Odd behaviour - Is it PHP bug?

I am not asking a typical question about why some code failed, yet I am asking about why it worked.It has worked with me while coding, and I needed it to fail.
Case
a base abstract class with a protected constructor declared abstract
a parent class extends the abstract class with public constructor (Over ridding)
a child class extends the very same abstract class with a protected constructor
abstract class BaseClass {
abstract protected function __construct();
}
class ChildClass extends BaseClass {
protected function __construct(){
echo 'It works';
}
}
class ParentClass extends BaseClass {
public function __construct() {
new ChildClass();
}
}
// $obj = new ChildClass(); // Will result in fatal error. Expected!
$obj = new ParentClass(); // that works!!WHY?
Question
Parent class instantiates child class object, and it works!!
how come it does?
as far as I know,object cannot be instantiated if its constructor declared protected, except only internally or from within any subclasses by inheritance.
The parent class is not a subclass of the child class,it doesn't inherit a dime from it ( yet both extend the same base abstract class), so how come instantiation doesn't fail?
EDIT
This case only happens with an abstract BaseClass that has also an abstract constructor.If BaseClass is concerete, or if its protected constructor is not abstract, instantiation fails as expected.. is it a PHP bug?
For my sanity, I need really an explanation to why PHP behaves this way in this very specific case.
Thanks in advance
Why it works?
Because from inside ParentClass you have granted access to the abstract method from BaseClass. It is this very same abstract method which is called from ChildClass, despite its implementation is defined on itself.
All relies in the difference between a concrete and an abstract method.
You can think like this: an abstract method is a single method with several implementations. On the other hand, each concrete method is a unique method. When it has the same name than its parent, it overrides the parent's one (it does not implement it).
So, when declared abstract, it is always the base class method which is called.
Think about a method declared abstract: Why the signatures of different implementations can't differ? Why can't the child classes declare the method with less visibility?
Anyway, you have just found a very interesting feature. Or, if my understanding above is not correct, and your expected behaviour is the truly expected behaviour, then you have found a bug.
Note: the following was tested with PHP 5.3.8. Other versions may exhibit different behavior.
Since there isn't a formal specification for PHP, there isn't a way of answering this from the point of view of what should happen. The closest we can get is this statement about protected from the PHP manual:
Members declared protected can be accessed only within the class itself and by inherited and parent classes.
Though the member may be overridden in ChildClass (keeping the "protected" specifier), it was originally declared in BaseClass, so it remains visible in descendants of BaseClass.
In direct opposition to this interpretation, compare the behavior for a protected property:
<?php
abstract class BaseClass {
protected $_foo = 'foo';
abstract protected function __construct();
}
class MommasBoy extends BaseClass {
protected $_foo = 'foobar';
protected function __construct(){
echo __METHOD__, "\n";
}
}
class LatchkeyKid extends BaseClass {
public function __construct() {
echo 'In ', __CLASS__, ":\n";
$kid = new MommasBoy();
echo $kid->_foo, "\n";
}
}
$obj = new LatchkeyKid();
Output:
In LatchkeyKid:
MommasBoy::__construct
Fatal error: Cannot access protected property MommasBoy::$_foo in - on line 18
Changing the abstract __construct to a concrete function with an empty implementation gives the desired behavior.
abstract class BaseClass {
protected function __construct() {}
}
However, non-magic methods are visible in relatives, whether or not they're abstract (most magic methods must be public).
<?php
abstract class BaseClass {
abstract protected function abstract_protected();
protected function concrete() {}
}
class MommasBoy extends BaseClass {
/* accessible in relatives */
protected function abstract_protected() {
return __METHOD__;
}
protected function concrete() {
return __METHOD__;
}
}
class LatchkeyKid extends BaseClass {
function abstract_protected() {}
public function __construct() {
echo 'In ', __CLASS__, ":\n";
$kid = new MommasBoy();
echo $kid->abstract_protected(), "\n", $kid->concrete(), "\n";
}
}
$obj = new LatchkeyKid();
Output:
In LatchkeyKid:
MommasBoy::abstract_protected
MommasBoy::concrete
If you ignore the warnings and declare magic methods (other than __construct, __destruct and __clone) as protected, they appear to be accessible in relatives, as with non-magic methods.
Protected __clone and __destruct are not accessible in relatives, whether or not they're abstract. This leads me to believe the behavior of abstract __construct is a bug.
<?php
abstract class BaseClass {
abstract protected function __clone();
}
class MommasBoy extends BaseClass {
protected function __clone() {
echo __METHOD__, "\n";
}
}
class LatchkeyKid extends BaseClass {
public function __construct() {
echo 'In ', __CLASS__, ": \n";
$kid = new MommasBoy();
$kid = clone $kid;
}
public function __clone() {}
}
$obj = new LatchkeyKid();
Output:
In LatchkeyKid:
Fatal error: Call to protected MommasBoy::__clone() from context 'LatchkeyKid' in - on line 16
Access to __clone is enforced in zend_vm_def.h (specifically, ZEND_CLONE opcode handler). This is in addition to access checks for methods, which may be why it has different behavior. However, I don't see special treatment for accessing __destruct, so there's obviously more to it.
Stas Malyshev (hi, Stas!), one of the PHP developers, took a look into __construct, __clone and __destruct and had this to say:
In general, function defined in base class should be accessible to all
[descendents] of that class. The rationale behind it is that if you define
function (even abstract) in your base class, you saying it will be
available to any instance (including extended ones) of this class. So
any descendant of this class can use it.
[...] I checked why ctor behaves differently, and it's because parent ctor
is considered to be prototype for child ctor (with signature
enforcement, etc.) only if it's declared abstract or brought from the
interface. So, by declaring ctor as abstract or making it part of the
interface, you make it part of the contract and thus accessible to all
hierarchy. If you do not do that, ctors are completely unrelated to each
other (this is different for all other non-static methods) and thus
having parent ctor doesn't say anything about child ctor, so parent
ctor's visibility does not carry over. So for ctor is not a bug. [Note: this is similar to J. Bruni's answer.]
I still think it's most probably a bug for __clone and __destruct.
[...]
I've submitted bug #61782 to track the issue with __clone and __destruct.
EDIT: constructors act differenlty... It's expected to work even without abstract classes but I found this test that tests the same case and it looks like it's a technical limitation - the stuff explained below doesn't work with constructors right now.
There's no bug. You need to understand that access attributes work with objects' context. When you extend a class, your class will be able to see methods in BaseClass' context. ChildClass and ParentClass both in BaseClass context, so they can see all BaseClass methods. Why do you need it? For polymorphism:
class BaseClass {
protected function a(){}
}
class ChildClass extends BaseClass {
protected function a(){
echo 'It works';
}
}
class ParentClass extends BaseClass {
public function b(BaseClass $a) {
$a->a();
}
public function a() {
}
}
No matter what child you pass into ParentClass::b() method, you'll be able to access BaseClass methods (including protected, because ParentClass is BaseClass child and children can see protected methods of their parents). The same behaviour applies to constructors and abstract classes.
I wonder if there isn't something buggy w/ the abstract implementation under the hood, or if there is a subtle issue going on that we're missing. Changing BaseClass from abstract to concrete produces the fatal error you're after though (classes renamed for my sanity)
EDIT: I agree w/ what #deceze is saying in his comments, that it is an edge case of abstract implementation and potentially a bug. This is at least a work-around that provides the expected behavior albiet some ugly technique (feigned abstract base class).
class BaseClass
{
protected function __construct()
{
die('Psuedo Abstract function; override in sub-class!');
}
}
class ChildClassComposed extends BaseClass
{
protected function __construct()
{
echo 'It works';
}
}
// Child of BaseClass, Composes ChildClassComposed
class ChildClassComposer extends BaseClass
{
public function __construct()
{
new ChildClassComposed();
}
}
PHP Fatal error: Call to protected ChildClassComposed::__construct()
from context 'ChildClassComposer' in
/Users/quickshiftin/junk-php/change-private-of-another-class.php on
line 46

Abstract private functions

The following code will have PHP unhappy that customMethod() is private. Why is this the case? Is visibility determined by where something is declared rather than defined?
If I wanted to make customMethod only visible to boilerplate code in the Template class and prevent it from being overriden, would I just alternatively make it protected and final?
Template.php:
abstract class Template() {
abstract private function customMethod();
public function commonMethod() {
$this->customMethod();
}
}
CustomA.php:
class CustomA extends Template {
private function customMethod() {
blah...
}
}
Main.php
...
$object = new CustomA();
$object->commonMethod();
..
Abstract methods cannot be private, because by definition they must be implemented by a derived class. If you don't want it to be public, it needs to be protected, which means that it can be seen by derived classes, but nobody else.
The PHP manual on abstract classes shows you examples of using protected in this way.
If you fear that customMethod will be called outside of the CustomA class you can make the CustomA class final.
abstract class Template{
abstract protected function customMethod();
public function commonMethod() {
$this->customMethod();
}
}
final class CustomA extends Template {
protected function customMethod() {
}
}
Abstract methods are public or protected. This is a must.
Nothing in PHP that is private in a child class is visible to a parent class. Nothing that is private in a parent class is visible to a child class.
Remember, visibility must flow between the child class up to the parent class when using abstract methods in PHP. Using the visibility private in this scenario with PHP would completely encapsulate CustomA::customMethod inside of CustomA. Your only options are public or protected visibility.
Since you cannot make an instance of the abstract class Template, privacy from client-code is maintained. If you use the final keyword to prevent future classes from extending CustomA, you have a solution. However, if you must extend CustomA, you will have to live with how PHP operates for the time being.

Categories