I have the next code
<?php
interface SimpleInterface
{
public function method(): self;
}
trait SimpleTrait
{
public function method(): self
{
return $this;
}
}
class SomeClass implements SimpleInterface
{
use SimpleTrait;
}
But PHP says that RenderableTrait->setLayout(layout:string) isn't compatible with RenderableInterface->setLayout(layout: string)
Obviously, because interface expects self as returned value, but in trait I return Trait itself and it's not compatible. Are there any solutions?
Change you return type self for SimpleInterface
https://3v4l.org/LTc8E
<?php
trait Test {
public function test() {
return $this;
}
}
class Foo {
use Test;
}
class Bar {
use Test;
}
$f = new Foo();
$b = new Bar();
// object(Foo)
var_dump($f->test());
// object(Bar)
var_dump($b->test());
//So for you case
interface SimpleInterface
{
public function method(): SimpleInterface;
}
trait SimpleTrait
{
// This method will work only in classes that implements SimpleInterface
public function method(): SimpleInterface
{
return $this;
}
}
class SomeClass implements SimpleInterface
{
// Traits $this is now SomeClass
use SimpleTrait;
}
$s = new SomeClass();
// object(SomeClass)
var_dump($s->method());
Related
How can I stub a method of an object that is hardcoded in app? In rspec there is a method allow_any_instance_of.
I can't reverse the dependency, the initialisation of the object should still be hardcoded.
So, I have ClassA
namespace App
class ClassA
{
public function doSomething(){
// more code
return($sth);
}
}
It is used in ClassB
namespace App
class ClassB
{
protected $instanceOfA;
public function __construct(){
$this->instnaceOfA = new ClassA();
}
public function methodToTest(){
$result = $this->instanceOfA->doSomething()
// more code
}
}
I think this is what you're looking for? a plugable interface? if you change the classB to ClassA on line 33 it will switch to the other class.
Interface TheInterface
{
public function doSomething();
}
class ClassA implements TheInterface
{
public function doSomething(){
echo __METHOD__;
}
}
class ClassB implements TheInterface
{
public function doSomething(){
echo __METHOD__;
}
}
class ClassProcess
{
protected $instance;
public function __construct(TheInterface $class){
$this->instance = $class;
}
public function methodToTest(){
$this->instance->doSomething();
}
}
$process = new ClassProcess(new ClassB());
$process->methodToTest();
My question would be best illustrated by the following example:
class a
{
function a()
{
return file_get_contents('http://some/third/party/service');
}
}
class b
{
function b()
{
$a = new a();
return $a->a() . ' Bar';
}
}
class testB extends test
{
function testB()
{
$b = new b();
// Here we need to override a::a() method in some way to always return 'Foo'
// so it doesn't depend on the third party service. We only need to check
// the $b::b() method's behavior (that it appends ' Bar' to the string).
// How do we do that?
$this->assert_equals('Foo Bar', $b->b());
}
}
Let me point out that I don't have the control over where class 'a' is being defined/included.
If you changed class b so that the instance of a can be passed in:
class b
{
function b($a = null)
{
if ($a == null) {
$a = new a();
}
return $a->a() . ' Bar';
}
}
...then for test, you can use a framework like Mockery to pass in a mocked instance of 'a' which always returns 'Foo'
use \Mockery as m;
class testB extends test
{
public function tearDown()
{
m::close();
}
public function testB()
{
$mockA = m::mock('a');
$mockA->shouldReceive('a')->times(1)->andReturn('foo');
$b = new b($mockA);
$this->assert_equals('Foo Bar', $b->b());
}
}
See the full docs and examples for Mockery here: http://docs.mockery.io/en/latest/getting_started/simple_example.html
You can eliminate your dependency like that:
First you create an interface that will list all methods you need:
interface Doer {
function a();
}
Then create an adapter class for you a class:
class ADoer implements Doer
{
protected $dependencyA;
public function __construct(A $dep) {
$this->dependencyA = $dep;
}
public function a() {
$this->dependencyA->a();
}
}
Now make your B class depends on Doer interface, not on A implementation:
class B {
private $doer;
public function __construct(Doer $a) {
$this->doer = $a;
}
public function b() {
$this->doer->a();
}
public function setDoer(Doer $a) {
$this->doer = $a;
}
//getDoer()
}
Now you can switch it at will:
class FooDoer implements Doer {
function a() {
//do whatever you want
}
}
$b->setDoer(new FooDoer());
$b->b();
I'm still learning OOP so this might not even be possible (although I would be surprised if so), I need some help calling another classes method.
For example in ClassA I have this method:
function getName()
{
return $this->name;
}
now from ClassB (different file, but in the same directory), I want to call ClassA's getName(), how do I do that? I tried to just do an include() but that does not work.
Thanks!
//file1.php
<?php
class ClassA
{
private $name = 'John';
function getName()
{
return $this->name;
}
}
?>
//file2.php
<?php
include ("file1.php");
class ClassB
{
function __construct()
{
}
function callA()
{
$classA = new ClassA();
$name = $classA->getName();
echo $name; //Prints John
}
}
$classb = new ClassB();
$classb->callA();
?>
If they are separate classes you can do something like the following:
class A
{
private $name;
public function __construct()
{
$this->name = 'Some Name';
}
public function getName()
{
return $this->name;
}
}
class B
{
private $a;
public function __construct(A $a)
{
$this->a = $a;
}
function getNameOfA()
{
return $this->a->getName();
}
}
$a = new A();
$b = new B($a);
$b->getNameOfA();
What I have done in this example is first create a new instance of the A class. And after that I have created a new instance of the B class to which I pass the instance of A into the constructor. Now B can access all the public members of the A class using $this->a.
Also note that I don't instantiate the A class inside the B class because that would mean I tighly couple the two classes. This makes it hard to:
unit test your B class
swap out the A class for another class
You would need to have an instance of ClassA within ClassB or have ClassB inherit ClassA
class ClassA {
public function getName() {
echo $this->name;
}
}
class ClassB extends ClassA {
public function getName() {
parent::getName();
}
}
Without inheritance or an instance method, you'd need ClassA to have a static method
class ClassA {
public static function getName() {
echo "Rawkode";
}
}
--- other file ---
echo ClassA::getName();
If you're just looking to call the method from an instance of the class:
class ClassA {
public function getName() {
echo "Rawkode";
}
}
--- other file ---
$a = new ClassA();
echo $a->getName();
Regardless of the solution you choose, require 'ClassA.php is needed.
File 1
class ClassA {
public $name = 'A';
public function getName(){
return $this->name;
}
}
File 2
include("file1.php");
class ClassB {
public $name = 'B';
public function getName(){
return $this->name;
}
public function callA(){
$a = new ClassA();
return $a->getName();
}
public static function callAStatic(){
$a = new ClassA();
return $a->getName();
}
}
$b = new ClassB();
echo $b->callA();
echo $b->getName();
echo ClassB::callAStatic();
How can I return an instance of the class being called, when the method is in a parent class.
Eg. In the example below, how can I return an instance of B if I call B::foo();?
abstract class A
{
public static function foo()
{
$instance = new A(); // I want this to return a new instance of child class.
... Do things with instance ...
return $instance;
}
}
class B extends A
{
}
class C extends A
{
}
B::foo(); // Return an instance of B, not of the parent class.
C::foo(); // Return an instance of C, not of the parent class.
I know I can do it something like this, but is there a neater way:
abstract class A
{
abstract static function getInstance();
public static function foo()
{
$instance = $this->getInstance(); // I want this to return a new instance of child class.
... Do things with instance ...
return $instance;
}
}
class B extends A
{
public static function getInstance() {
return new B();
}
}
class C extends A
{
public static function getInstance() {
return new C();
}
}
$instance = new static;
You're looking for Late Static Binding.
http://www.php.net/manual/en/function.get-called-class.php
<?php
class foo {
static public function test() {
var_dump(get_called_class());
}
}
class bar extends foo {
}
foo::test();
bar::test();
?>
Result
string(3) "foo"
string(3) "bar"
So your function is going to be:
public static function foo()
{
$className = get_called_class();
$instance = new $className();
return $instance;
}
All you need is :
abstract class A {
public static function foo() {
$instance = new static();
return $instance ;
}
}
Or
abstract class A {
public static function foo() {
$name = get_called_class() ;
$instance = new $name;
return $instance ;
}
}
Suppose we have a class. We create an object from the class and when we do the class Extends himself base on the object initialization value..
For example:
$objectType1 = new Types(1);
$objectType1->Activate(); // It calls an activation function for type 1
$objectType2 = new Types(2);
$objectType2->Activate(); // It calls an activation function for type 2
I don't want to use the standard procedure of class extending:
class type1 extends types{}
You cannot extend a class at runtime. Use an instance variable to distinct the two type or use a factory.
Example for instance variable:
class Types() {
private $type;
public function __construct($type) {
$this->type = $type;
}
public function activate() {
if($this->$type == 1) {
// do this
}
else if($this->type == 2) {
// do that
}
}
}
Example for factory pattern:
abstract class BaseClass {
// Force Extending class to define this method
abstract public function activate();
// Common method
public function printOut() {
echo "Hello World";
}
}
class Type1 extends BaseClass {
public function activate() {
// do something
}
}
class Type2 extends BaseClass {
public function activate() {
// do something else
}
}
class TypeFactory {
public static function getType($tpye) {
if($type == 1) {
return new Type1();
}
else if($type == 2) {
return new Type2();
}
}
}
then you do:
$obj = TypeFactory::getType($1);
$obj->activate();
Update:
Since PHP 5.3 you can use anonymous functions. Maybe you can make use of this.