I am having a PHP interface coding problem. I took java code from the book “Head First Design Patterns and converted it to the code below. I am using MAMP/ PHP 5.6.2 and NetBeans 8.1.
I am trying to implement an interface “TestInterface” in the Menu class that extends an abstract class (MenuComponent). The Menu class will not start with the “TestInterface” implementation. The code runs when I comment out “TestInterface" in the Menu class declaration as the code below. And while “TestInterface” is commented out, PHP throws no errors even when declaring the interface and keeping the interface function as a Menu member function. I have successfully ran simpler code while extending and implementing at the same time using the same platform as stated above. Because of success with simpler code, I believe there is structural or syntax error in my code below. I hoping that someone can help me find what I am doing wrong. Thanks in advance.
<?php
$run = new myclass;
$run->main();
class myclass {
private $pancakeHouseMenu;
private $allMenus;
private $waitress;
public function main(){
echo "<br />hi main!<br />";
$this->pancakeHouseMenu = new Menu("PANCAKE HOUSE MENU", "Breakfast");
$this->allMenus = new Menu("ALL MENUS", "All menus combind");
$this->allMenus->add($this->pancakeHouseMenu);
$this->pancakeHouseMenu->add(new MenuItem(
"Regular Pancake Breakfast",
"Pancakes with eggs and sausage"));
$this->waitress = new Waitress($this->allMenus);
$this->waitress->printMenu();
}
}
interface TestInterface {
public function interfaceTest();
}
abstract class MenuComponent {
public function add(MenuComponent $newMenuComponent) {
throw new InvalidArgumentException("Exception thrown");
}
public function getName() {
throw new InvalidArgumentException("Exception thrown");
}
public function getDescription() {
throw new InvalidArgumentException("Exception thrown");
}
public function printOut() {
throw new InvalidArgumentException("Exception thrown");
}
}
class Waitress {
private $allMenus;
public function __construct(MenuComponent $allMenus) {
$this->allMenus = $allMenus;
$this->allMenus->add($allMenus);
}
public function printMenu() {
$this->allMenus->printOut();
}
}
class MenuItem extends MenuComponent {
private $name;
private $description;
public function __construct($name, $description) {
$this->name = $name;
$this->description = $description;
}
public function getName() {
return $this->name;
}
public function getDescription() {
return $this->description;
}
public function printOut() {
print(" " . $this->getName());
print(" -- " . $this->getDescription());
}
}
class Menu extends MenuComponent /*** implements TestInterface ***/ {
private $menuComponents = array();
private $name;
private $description;
// private $testVar;
public function __construct($name, $description) {
$this->name = $name;
$this->description = $description;
$this->testVar = "Interface test succeeded";
}
public function interfaceTest(){
return $this->testVar;
}
public function add(MenuComponent $newMenuComponent) {
array_push($this->menuComponents, $newMenuComponent);
}
public function getName() {
return $this->name;
}
public function getDescription() {
return $this->description;
}
public function printOut() {
print("<br />" . $this->getName());
print(", " . $this->getDescription());
print("<br />---------------------");
print("<br />Testing interface var: ". $this->interfaceTest());
}
}
?>
In your code you create an object above the declaration of your classes. This seems to be ok if your classes do not implement any interfaces. Since your class menu does implement the interface TestInterface, PHP does not accept your object instantiation before the declaration of your classes.
The solution is quite simple, place your object creation of myclass below the object declaration:
<?php
class myclass {
private $pancakeHouseMenu;
private $allMenus;
private $waitress;
...
public function getDescription() {
return $this->description;
}
public function printOut() {
print("<br />" . $this->getName());
print(", " . $this->getDescription());
print("<br />---------------------");
print("<br />Testing interface var: ". $this->interfaceTest());
}
}
$run = new myclass;
$run->main();
?>
Related
I am getting this error:
uncaught error call to undefine method
Vehicles::setPassengerSeats() in
C:\xampp\htdocs\practice\vehicle.php:91.
I also have added screenshot of the error. Kindly check and tell me how can i solve it ? I think i have problem with my sub class but i don't know where?
Here is my source code:
<?php
class Vehicles{
private $noOfVehicles;
private $color;
private $fuel;
private $speed;
public function getNoOfVehicles(){
return $this->noOfMobiles;
}
public function setNoOfVehicles($Vehicles){
$this->noOfMobiles = $Vehicles;
echo "No of Vehicles are: ".$this->noOfVehicles."</br>";
}
public function getColor(){
return $this->color;
}
public function setColor($look){
$this->color = $look;
echo "</br>The Color of Vehicle is: ".$this->color."</br>";
}
public function getFuel(){
return $this->fuel;
}
public function setFuel($petrol){
$this->fuel = $petrol;
echo "</br>The fuel is: ".$this->color."</br>";
}
public function getSpeed(){
return $this->speed;
}
public function setSpeed($vehicleSpeed){
$this->speed = $vehicleSpeed;
echo "</br>The speed of vehicle is: ".$this->speed."</br>";
}
}
class PassengerVehicles extends Vehicles{
private $passengerSeats;
public function getPassengerSeats(){
return $this->passengerSeats;
}
public function setPassengerSeats($seats){
return $this->passengerSeats = $seats;
echo "</br>Passenger Seats are: ".$this->passengerSeats."</br>";
}
}
class TransportationVehicles extends Vehicles{
private $noOfDoors;
private $loadCapacity;
public function getNoOfDoors(){
return $this->noOfDoors;
}
public function setNoOfDoors($doors){
return $this->noOfDoors = $doors;
echo "</br>The No of Doors are: ".$this->noOfDoors."</br>";
}
public function getLoadCapacity(){
return $this->loadCapacity;
}
public function setLoadCapacity($capacity){
return $this->loadCapacity = $capacity;
echo "The Load Capacity is: ".$this->loadCapacity."</br>";
}
}
$VehiclesObj = new Vehicles;
$VehiclesObj->setNoOfVehicles("15");
$VehiclesObj->setColor("Black");
$VehiclesObj->setFuel("5 Litre");
$VehiclesObj->setSpeed("120 km/h");
$VehiclesObj->setPassengerSeats("4");
$VehiclesObj->setNoOfDoors("4");
$VehiclesObj->setLoadCapacity("500 KG");
?>
You call method setPassengerSeats which is in another class not in Vehicles You should create instance first, then to call this method:
$passangerVehicle = new PassengerVehicles;
$passangerVehicle->setPassengerSeats("4");
You can't call child methods from a parent. You need to create an instance of the child to be able to call parent methods
class Vehicles{
private $noOfVehicles;
private $color;
private $fuel;
private $speed;
public function getNoOfVehicles(){
return $this->noOfMobiles;
}
public function setNoOfVehicles($Vehicles){
$this->noOfMobiles = $Vehicles;
echo "No of Vehicles are: ".$this->noOfVehicles."</br>";
}
public function getColor(){
return $this->color;
}
public function setColor($look){
$this->color = $look;
echo "</br>The Color of Vehicle is: ".$this->color."</br>";
}
public function getFuel(){
return $this->fuel;
}
public function setFuel($petrol){
$this->fuel = $petrol;
echo "</br>The fuel is: ".$this->color."</br>";
}
public function getSpeed(){
return $this->speed;
}
public function setSpeed($vehicleSpeed){
$this->speed = $vehicleSpeed;
echo "</br>The speed of vehicle is: ".$this->speed."</br>";
}
}
class PassengerVehicles extends Vehicles{
private $passengerSeats;
public function getPassengerSeats(){
return $this->passengerSeats;
}
public function setPassengerSeats($seats){
return $this->passengerSeats = $seats;
echo "</br>Passenger Seats are: ".$this->passengerSeats."</br>";
}
}
class TransportationVehicles extends Vehicles{
private $noOfDoors;
private $loadCapacity;
public function getNoOfDoors(){
return $this->noOfDoors;
}
public function setNoOfDoors($doors){
$this->noOfDoors = $doors;
echo "</br>The No of Doors are: {$this->noOfDoors}</br>";
return $this->noOfDoors;
}
public function getLoadCapacity(){
return $this->loadCapacity;
}
public function setLoadCapacity($capacity){
return $this->loadCapacity = $capacity;
echo "The Load Capacity is: ".$this->loadCapacity."</br>";
}
}
$truck = new TransportationVehicles();
$truck->setNoOfVehicles("15");
$truck->setColor("Black");
$truck->setFuel("5 Litre");
$truck->setSpeed("120 km/h");
$truck->setNoOfDoors("4");
$truck->setLoadCapacity("500 KG");
$taxi = (new PassengerVehicles())->setPassengerSeats('4');
In this case, you will have two instances of the Vehicles class + own child.
The first instance is related to the Vehicle itself + transport properties like $noOfDoorsand $loadCapacity - a truck for example.
The second is an instance of a passenger based vehicle - taxi for example.
And you tried to get passengers option of a taxi from a bus.
I am noob in PHP because I am mostly do .NET/Java. In code base I am working, I have,
class SomeOtherBaseClass{
public $prop2;
public function __construct(string $prop3)
{
$this->prop2 = $prop3;
}
public function __toString()
{
return $this->prop2 . ' '. $this->prop2;
}
}
class SomeClass
{
public function __toString()
{
return $this->prop1 . ' '. $this->prop1;
}
public $prop1;
public function someMethod() : SomeOtherBaseClass
{
return $this->createClass();
}
public function __construct()
{
$this->prop1 = 'foo';
}
private function createClass(
): SomeOtherBaseClass {
return new class(
$this->prop1
) extends SomeOtherBaseClass {
};
}
}
$class = new SomeClass();
echo $class;
echo $class->someMethod();
Why I am getting error that prop1 not found. Clearly createClass function is part of SomeClass which have prop1. Why I cannot access prop1 inside createClass?
It's because $prop1 has no value or meaning.
You can add a __construct() function to resolve your issue:
public function __construct()
{
$this->prop1 = 'foo';
}
now when you call this class (e.g. $foo = new SomeClass();):
$prop1 has a value of foo which can be used in your functions:
public function echoProp()
{
echo $this->prop1; # will output foo
}
Note: This is just an explanation answer - not a copy/paste solution - but the principles are all here for you to use in your code.
Let me know if this wasn't what you were looking for :)
Edit:
if prop1 exists in SomeOtherClass, when you construct you can do
public function __construct()
{
$this->class = new SomeClass();
$this->prop1 = $this->class->prop1;
}
I'm wondering if its possible to switch the visibility in PHP. Let me demonstrate:
class One {
function __construct($id){
if(is_numeric($id)){
//Test function becomes public instead of private.
}
}
private function test(){
//This is a private function but if $id is numeric this is a public function
}
}
Is such thing even possible?
I would use an abstract class with two implementing classes: One for numeric and one for non-numeric:
abstract class One {
static function generate($id) {
return is_numeric($id) ? new OneNumeric($id) : new OneNonNumeric($id);
}
private function __construct($id) {
$this->id = $id;
}
}
class OneNumeric extends One {
private function test() {
}
}
class OneNonNumeric extends One {
public function test() {
}
}
$numeric = One::generate(5);
$non_numeric = One::generate('not a number');
$non_numeric->test(); //works
$numeric->test(); //fatal error
It can be faked up to a point with magic methods:
<?php
class One {
private $test_is_public = false;
function __construct($id){
if(is_numeric($id)){
$this->test_is_public = true;
}
}
private function test(){
echo "test() was called\n";
}
public function __call($name, $arguments){
if( $name=='test' && $this->test_is_public ){
return $this->test();
}else{
throw new LogicException("Method $name() does not exist or is not public\n");
}
}
}
echo "Test should be public:\n";
$numeric = new One('123e20');
$numeric->test();
echo "Test should be private:\n";
$non_numeric = new One('foo');
$non_numeric->test();
I haven't thought about the side effects. Probably, it's only useful as mere proof of concept.
The following code taken from a 2010 PHP book I a m currently reading returns a "Fatal error: Call to a member function getPrice() on a non-object in Z:\home\different-tasks\www\cardecorator.php on line 15" How come that a car is not an object?
<?php
abstract class AbstractCar {
public abstract function getPrice();
public abstract function getManufacturer();
};
class Car extends AbstractCar {
private $price = 16000;
private $manufacturer = 'Acme Autos';
public function getPrice() { return $this->price; }
public function getManufacturer() { return $this->manufacturer; }
};
class CarDecorator extends AbstractCar {
private $target;
function __construct( Car $target ) { $this->target = $target; }
public function getPrice() { return $target->getPrice(); }
public function getManufacturer() { return $target->getManufacturer(); }
};
class NavigationSystem extends CarDecorator {
public function getPrice() { return parent::getPrice()+1000; }
};
$car = new Car();
$car = new NavigationSystem( $car );
//$car = new LeatherSeats( $car );
echo $car->getPrice();
public function getPrice() { return $target->getPrice(); }
should be
public function getPrice() { return $this->target->getPrice(); }
you have several mistakes like this there
I went on to download the examples from the publisher's site, and the downloadsable code works. The author explicitly mentioned in the preface that some elements of the examples given in the printed version might be missing to provide conciseness.
So,I guess that I should study the code that is downloaded rather than what is printed.
Bellow is a PHP script.
I tried to implement the Observer pattern (without MVC structure)... only basic.
The error which is encountered has been specified in a comment.
First I tried to add User objects to the UsersLibrary repository. There was a error such as User::update() does not exists or something.
Why is that error encountered? What fix should be applied and how?
interface IObserver {
public function update(IObservable $sender);
}
interface IObservable {
public function addObserver(IObserver $obj);
public function notify();
}
class UsersLibrary implements IObservable {
private $container;
private $contor;
//private $z;
public function __construct() {//IObserver $a) {
$this->container = array();
$this->contor = 0;
echo "<div>[constructing UsersLibrary...]</div>";
$this->addObserver(new Logger());
//$this->z = $a;
}
public function add($obj) {
echo "<div>[adding a new user...]</div>";
$this->container[$this->contor] = $obj;
$this->contor++;
$this->notify();
}
public function get($index) {
return $this->container[$index];
}
public function addObserver(IObserver $obj) {
$this->container[] = $obj;
}
public function notify() {
echo "<div>[notification in progress...]</div>";
foreach($this->container as $temp) {
//echo $temp;
#################################################################
$temp->update(); //--------ERROR
//Fatal Error: Call to a member function update() on a non-object.
#################################################################
}
//$this->container[0]->update();
//$this->z->update($this);
}
}
class User {
private $id;
private $name;
public function __construct($id, $name) {
$this->id = $id;
$this->name = $name;
}
public function getId() {
return $this->id;
}
public function getName() {
return $this->name;
}
}
class Logger implements IObserver {
public function __construct() {
echo "<div>[constructing Logger...]</div>";
}
public function update(IObservable $sender) {
echo "<div>A new user has been added.</div>";
}
}
$a = new UsersLibrary(); //new Logger());
//$a->add(new User(1, "DemoUser1"));
//$a->add(new User(2, "DemoUser2"));
$a->add("Demo");
echo $a->get(0);
//echo $a->get(0)->getName();
Your User class is not implementing interface IObserver and therefore is not forced to have the method update().
You have to instantiate a new User() in order to add it to the UsersLibrary:
$library = new UsersLibrary();
$user = new User(1, "Demo");
$library->add($user);
Also, you are mixing Users and Loggers into your UsersLibrary container. Maybe think about separating the containers for them?
You are passing a string instead of an object in your $a->add() call. You should either pass in an object, or alter the code in UserLibrary::add() to wrap it's argument in an appropriate object (or do an object lookup of it sees a string, for instance find a user with that name).
$user = new User(1, "Demo");
$a = new UsersLibrary();
$a->add($user);