I am studying Head First - design patterns and translating the exercises to PHP.
I dont get any errors but there is a bug that I cannot figure out.
Edit ( Code ):
abstract class Cat
{
public $meowBehaviour, $eatBehaviour;
function __construct(MeowBehaviour $meowBehaviour, EatBehaviour $eatBehaviour)
{
$this->meowBehaviour = $meowBehaviour;
$this->eatBehaviour = $eatBehaviour;
}
public abstract function sits();
public function performMeowBehaviour()
{
$this->meowBehaviour->meow();
}
public function performEatBehaviour()
{
$this->eatBehaviour->eat();
}
}
interface EatBehaviour {
public function eat();
}
class EatCatFood implements EatBehaviour {
public function eat()
{
echo "I eat cat food. <br />";
}
}
class EatGazzelle implements EatBehaviour {
public function eat()
{
echo "I hunt and eat gazzelle. <br />";
}
}
interface MeowBehaviour {
public function meow();
}
class Meow implements MeowBehaviour {
public function meow()
{
echo "meow <br />";
}
}
class Roar implements MeowBehaviour {
public function meow()
{
echo "ROAR! <br />";
}
}
class HouseCat extends Cat
{
function __construct()
{
parent::__construct(new Meow, new EatCatFood);
}
public function sits()
{
echo "if I fits I sits";
}
}
class CatSimulator {
public $cat;
public function __construct()
{
$this->cat = new HouseCat;
$this->cat->performMeowBehaviour();
$this->cat->performEatBehaviour();
}
}
$c = new CatSimulator;
the output from CatSimulator is
meow
meow
I eat cat food.
I cannot figure out why 'meow' is repeated.
In PHP function names are case-insensitive. So here:
class Meow implements MeowBehaviour {
public function meow()
{
echo "meow <br />";
}
}
... meow() is treated as a constructor (PHP 4.x style) - and gets called on $this->cat = new HouseCat; line, echoing the first 'meow'.
You can rename the class, of course, but there's another alternative: add explicit constructor in that class, as here:
class Meow implements MeowBehaviour {
public function __construct() {}
public function meow()
{
echo "meow <br />";
}
}
Now meow method will be called only once.
It's important that __construct() precedes meow(), otherwise E_STRICT error will be raised. You can read more about it here.
Related
I'm trying to set the "setFlyBhavior(FlyBehavior $newFlyBehavior)" dynamically. Can anyone explain why it will not work in the code below? I appreciate your help.
<?php
abstract class Duck {
public $flyBehavior;
public function performFly() {
return $this->flyBehavior->fly();
}
public function setFlyBhavior(FlyBehavior $newFlyBehavior) {
$this->flyBehavior = $newFlyBehavior;
}
}
interface FlyBehavior {
public function fly();
}
class GotWings implements FlyBehavior {
public function fly(){
return "<br />I'm flying with wings!!<br />";
}
}
class NotWings implements FlyBehavior {
public function fly(){
return "<br />I can't fly I have no wings!!<br />";
}
}
class FlyingDuck extends Duck {
public function __construct(){
$this->flyBehavior = new GotWings();
}
}
$ducky = new FlyingDuck();
// Code works when the setFlyBehavior function is commented out.
$ducky->setFlyBehavior(new NoWings);
echo "<br />I'm a Duck: " . $ducky->performFly();
?>
Note: The code works when not calling the "ducky->setFlyBehavior function. I also tried defining the setFlyBehavior function in the Duck class without using type casting, which also failed e.g.
public function setFlyBhavior($newFlyBehavior) {
$this->flyBehavior = $newFlyBehavior;
}
You are calling the wrong function and class names.
Replace the line:
$ducky->setFlyBehavior(new NoWings);
With:
$ducky->setFlyBhavior(new NotWings);
I have two classes A and B. Class C may be extends A and B. I need to do it optimally.
class A {
public function testA() {
echo "this is function testA \n";
}
}
class B {
public function testB() {
echo "this is function testB \n";
}
}
class C extends A {
public function __call($method, $args){
$this->b =new B();
try {
return !method_exists ($this->b , $method ) || !$this->b->$method($args[0]);
} catch(Exception $e) {
echo "error";
}
}
}
$object = new C();
$object->testA();
$object->testB();
$object->testD();
How I can optimize this code?
Multiple "inheritance" in PHP is handled by Traits, which are available as of 5.4.0
More info here: http://php.net/manual/en/language.oop5.traits.php
trait A {
public function testA() {
echo "this is function testA \n";
}
}
trait B {
public function testB() {
echo "this is function testB \n";
}
}
class C {
use A, B;
public function __call($method, $args){
// Called method does not exists.
}
}
cook looks like this:
abstract class Foo
{
pulbic function __construct()
{
if (method_exists($this, 'beforeConstruct')) {
$this->beforeConstruct();
}
if (method_exists($this, 'afterConstruct')) {
$this->afterConstruct();
}
}
}
class Bar extends Foo
{
public function beforeConstruct()
{
echo 'Before Construct.<br>';
}
public function __construct()
{
echo 'Clas Bar has been created.<br>'
}
public function beforeConstruct()
{
echo 'After Construct.<br>';
}
}
$bar = new Bar();
but not working, somebody can help me? how to return results like this:
Before Construct.
Class Bar has been created.
After Construct.
First call the constructor of the parent from the child class constructor , which in turn calls the method beforeConstruct() of the child class and after that it prints the Clas Bar has been created. after that it fires the destructor of your child class.
<?php
abstract class Foo
{
public function __construct()
{
if (method_exists($this, 'beforeConstruct')) {
$this->beforeConstruct();
}
if (method_exists($this, 'afterConstruct')) {
$this->afterConstruct();
}
}
}
class Bar extends Foo
{
public function __construct()
{
parent::__construct();
echo 'Clas Bar has been created.<br>';
}
public function beforeConstruct()
{
echo 'Before Construct.<br>';
}
public function __destruct()
{
echo 'After Construct.<br>';
}
}
$bar = new Bar();
OUTPUT:
Before Construct.
Clas Bar has been created.
After Construct.
I have the following class and I want to implement chaining methods. I am kinda teaching my ownself so I thought it would be neat to test chaining. However that didnt work. What would I need to do that
echo $animal->name.' says'.$animal->speak()->likes()."<br />";
here is my complete code
<?php
class Animal{
var $name;
function __construct(){
$this->name = $name;
}
}
class Dog extends Animal{
public function speak(){
return "Woof Woof";
}
public function likes(){
return "steaks";
}
}
class Cat extends Animal{
public function speak(){
return "Meow Meow";
}
public function likes(){
return "tuna";
}
}
$animals = array(new Dog('skippy'), new Cat('snowball'));
foreach($animals as $animal){
echo $animal->name.' says'.$animal->speak()->likes()."<br />";
}
?>
<?php
class Animal {
function speak() {
echo "Random Noise!\n";
return $this;
}
}
class Dog extends Animal {
function bark() {
echo "bark!\n";
return $this;
}
}
$a = new Dog();
$a->speak()->bark();
You need to return $this in order to chain your methods.
If you want to chain method, you need to return $this in the method for chaining.
try to write instead of
echo $animal->name.' says'.$animal->speak()->likes()."<br />";
that :
printf('%s says %s %s',#animal->name,$animal->speak()->likes());
this is my class:
class toyota extends car {
function drive() {
}
function break() {
}
}
class car {
function pre() {
}
}
Is there any way I can do so that when I run $car->drive(), $car->break() (or any other function in toyota), it would call $car->pre() first before calling the functions in toyota?
Yep. You could use protected and some __call magic:
class toyota extends car {
protected function drive() {
echo "drive\n";
}
protected function dobreak() {
echo "break\n";
}
}
class car {
public function __call($name, $args)
{
if (method_exists($this, $name)) {
$this->pre();
return call_user_func_array(array($this, $name), $args);
}
}
function pre() {
echo "pre\n";
}
}
$car = new toyota();
$car->drive();
$car->dobreak();
http://ideone.com/SGi1g
You could do the following, but I don't think that is what you want.
class toyota extends car {
function drive() {
$this->pre();
}
function break() {
$this->pre();
}
}
class car {
function pre() {
}
}
You may want to look into PHP specific magic methods. http://php.net/manual/en/language.oop5.magic.php
This will better done with the magic methods called __call()
public function __call($name, $arguments)
{
$this -> pre();
return $this -> $name($arguments);
}
What is this method? It overrides the default method call, so that preCall State can be invoked.
Your toyota class
class toyota extends car {
public function __call($name, $arguments)
{
$this -> pre();
return call_user_func_array(array($this, $name), $arguments);
}
function drive() {
}
function break() {
}
}
If you are using PHP5 (>=5.3.2), there is a solution that works with declaring all methods as private. This will enforce method call from single function call:
exec_method()
To run at: http://ideone.com/cvfCXm
The code snippet is here:
<?php
class car {
//method to get class method
public function get_method($method_name) {
$class = new ReflectionClass(get_class($this));
$method = $class->getMethod($method_name);
$method->setAccessible(true);
return $method;
}
public function exec_method($method_name, $arg_args=array()) {
//execute the pre() function before the specified method
$this->pre();
//execute the specified method
$this->get_method($method_name)->invokeArgs($this, $arg_args);
}
public function pre() {
echo 'pre';
echo '<br />';
}
}
class toyota extends car {
private function drive() {
echo 'drive';
echo '<br />';
}
private function brake() {
echo 'brake';
echo '<br />';
}
}
$toyota = new toyota();
$toyota->exec_method('drive');
$toyota->exec_method('brake');
?>
Reference:
Answer to Best practices to test protected methods with PHPUnit [closed]
Just add a constructor, like this...
class toyota extends car {
function __construct() {
$this->pre();
}
function drive() {
echo "drive!";
}
function dobreak() {
echo "break!";
}
}
class car {
function pre() {
echo "Hello!";
}
}
$car = new toyota();
$car->drive();
$car->dobreak();
Classes which have a constructor method call this method on each
newly-created object, so it is suitable for any initialization that
the object may need before it is used.
break is reserved, so you shouldn't use this as a function name.