I have a problem with an error I am getting that says:
Class Car contains 1 abstract method and must therefore be decla
red abstract or implement the remaining methods (Car::accelerate) in C:\xampp
\htdocs\php\learn_php_oop\Car.php on line 58.
This is the code in two files I am using:
Car.php
<?php
/**
* represents generic properties and methods for any type of car
*/
class Car
{
protected $colour, $doorNumber, $fuelType, $rightHandDrive, $accelerate;
public function __construct($rightHandDrive = true)
{
$this->rightHandDrive = $rightHandDrive;
}
public function getColour()
{
return $this->colour;
}
public function setColour($colour)
{
$this->colour = $colour;
}
public function getDoorNumber()
{
return $this->doorNumber;
}
public function setDoorNumber($doorNumber)
{
$this->doorNumber = $doorNumber;
}
public function getFuelType()
{
return $this->fuelType;
}
public function setFuelType($fuelType)
{
$this->fuelType = $fuelType;
}
public function getRightHandDrive()
{
return $this->rightHandDrive;
}
public function setRightHandDrive($rightHandDrive)
{
$this->rightHandDrive = $rightHandDrive;
}
abstract protected function accelerate();
}
?>
Sport_car.php
<?php
include ('Car.php');
/**
* represents sport cars
*/
class Sport_car extends Car
{
public function accelerate()
{
$this->accelerate = 5;
}
}
?>
I have spent some time trying to figure out why this is happening but I just do not know why? Please help.
It's an OOP problem, in your case you must declare your Car Object as Abstract like this :
<?php
/**
* represents generic properties and methods for any type of car
*/
abstract class Car
{
protected $colour, $doorNumber, $fuelType, $rightHandDrive, $accelerate;
public function __construct($rightHandDrive = true)
{
$this->rightHandDrive = $rightHandDrive;
}
public function getColour()
{
return $this->colour;
}
public function setColour($colour)
{
$this->colour = $colour;
}
public function getDoorNumber()
{
return $this->doorNumber;
}
public function setDoorNumber($doorNumber)
{
$this->doorNumber = $doorNumber;
}
public function getFuelType()
{
return $this->fuelType;
}
public function setFuelType($fuelType)
{
$this->fuelType = $fuelType;
}
public function getRightHandDrive()
{
return $this->rightHandDrive;
}
public function setRightHandDrive($rightHandDrive)
{
$this->rightHandDrive = $rightHandDrive;
}
abstract protected function accelerate();
}
?>
Explanations :
A class wich is extended with at least one abstract method in it has to be defined as abstract itself, otherwise you'll get an error
Related
I have the following code
<?php
class ingredient {
private $calories;
public function __construct() {
$this->calories = 100;
}
public function get_calories() {
return $this->calories;
}
}
class flour extends ingredient {
private $texture;
public function __construct(texture) {
$this->texture = $texture;
}
public function get_texture() {
return $this->texture;
}
}
$plain_flour = new flour("Grainy");
My question is, does plain_flour have the attribute calories initialized already? Can I call get_calories on plain_flour? If no, how can I make it work so flour has the calories attribute ready to go and I can use the get_calories function
Since the $calories element is part of the ingredient class and is a private variable.
To access the variable from the flour class, you can call the parent's __construct method.
See this:
class ingredient {
private $calories;
public function __construct() {
$this->calories = 100;
}
public function get_calories() {
return $this->calories;
}
}
class flour extends ingredient {
private $texture;
public function __construct($texture) {
$this->texture = $texture;
parent::__construct();
}
public function get_texture() {
return $this->texture;
}
}
$plain_flour = new flour("Grainy");
echo $plain_flour->get_calories();
I have a class that is using the State pattern. Here's a simple example
/**
* #Enitity
**/
class Door
{
protected $id;
protected $state;
public function __construct($id, DoorState $state)
public function setState(DoorState $state)
{
$this->state = $state;
}
public function close()
{
$this->setState($this->state->close())
}
...
}
interface DoorState
{
public function close;
public function open;
public function lock;
public function unlock;
}
class DoorAction implements DoorState
{
public function close()
{
throw new DoorError();
}
...
}
then several classes that define the appropriate actions in the states
class OpenedDoor extends DoorAction
{
public function close()
{
return new ClosedDoor();
}
}
So I would have some thing like
$door = new Door('1', new OpenedDoor());
DoctrineDoorRepository::save($door);
$door->close();
DoctrineDoorRepository::save($door);
How would I implement the mapping in Doctrine so I can persist it?
I'm hung up on the $state property. I would like to save the whole DoorAction based object but do I have to the map the DoorAction super class or each individual sub class?
I've looked at implementing it using Embeddable or SuperMapping but run into problems with each.
Doctrine2 DBAL has a feature in the documentation that allows ENUM's
https://www.doctrine-project.org/projects/doctrine-orm/en/current/cookbook/mysql-enums.html#mysql-enums
When we take the Solution 2: Defining a Type as a base, one could create an own type, for instance called doorstatetype or similar to represent the open/closed state. For instance like this:
<?php
namespace Acme\Model\Door;
use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Platforms\AbstractPlatform;
class DoorStateType extends Type
{
const ENUM_DOORSTATE = 'enumdoorstate';
const STATE_OPEN = 'open';
const STATE_CLOSED = 'closed';
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
{
return "ENUM('" . self::STATE_OPEN . "', '" . self::STATE_CLOSED . "') COMMENT '(DC2Type:" . ENUM_DOORSTATE . ")'";
}
public function convertToPHPValue($value, AbstractPlatform $platform)
{
return $value;
}
public function convertToDatabaseValue($value, AbstractPlatform $platform)
{
if (!in_array($value, array(self::STATE_OPEN, self::STATE_CLOSED))) {
throw new \InvalidArgumentException("Invalid state");
}
return $value;
}
public function getName()
{
return self::ENUM_DOORSTATE;
}
}
And then use it like this:
<?php
namespace Acme\Model\Door;
/** #Entity */
class Door
{
/** #Column(type="enumdoorstate") */
private $state;
public function open()
{
if (!DoorStateType::STATE_OPEN === $this->state) {
throw new \LogicException('Cannot open an already open door');
}
$this->state = DoorStateType::STATE_OPEN;
}
public function close()
{
if (!DoorStateType::STATE_CLOSED === $this->state) {
throw new \LogicException('Cannot close an already closed door');
}
$this->state = DoorStateType::STATE_CLOSED;
}
}
This allows searching for states:
$openDoors = $repository->findBy(array('state' => DoorStateType::STATE_OPEN));
You could basically then have the convertToPHPValue method create objects of the desired states that allow for some logic, like checking if an open door can be locked or similar.
In the case where the state has to be a class that contains logic, you could implement it like this:
First we define a normal state from which we can inherit:
<?php
namespace Acme\Model\Door;
abstract class DoorState
{
// Those methods define default behaviour for when something isn't possible
public function open()
{
throw new \LogicException('Cannot open door');
}
public function close()
{
throw new \LogicException('Cannot close door');
}
abstract public function getStateName();
}
Then the OpenState:
<?php
namespace Acme\Model\Door;
class OpenState extends DoorState
{
const STATE = 'open';
public function close()
{
return new ClosedState();
}
public function getStateName()
{
return self::STATE;
}
// More logic
}
And finally the ClosedState:
<?php
namespace Acme\Model\Door;
class ClosedState extends DoorState
{
const STATE = 'closed';
public function open()
{
return new OpenState();
}
public function getStateName()
{
return self::STATE;
}
// More logic
}
We can then, for persistence, simply use different convert methods:
<?php
namespace Acme\Model\Door;
use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Platforms\AbstractPlatform;
class DoorStateType extends Type
{
// SQL declarations etc.
public function convertToPHPValue($value, AbstractPlatform $platform)
{
if ($value === OpenState::STATE) {
return new OpenState();
}
if ($value === ClosedState::STATE) {
return new ClosedState();
}
throw new \Exception(sprintf('Unknown state "%s", expected one of "%s"', $value, implode('", "', [OpenState::STATE, ClosedState::STATE])));
}
public function convertToDatabaseValue($value, AbstractPlatform $platform)
{
return $value->getStateName();
}
}
What if you map state as a string and then:
public function setState(DoorState $state)
{
$this->state = serialize($state);
}
and:
private function state()
{
return unserialize($this->state);
}
public function close()
{
$this->setState($this->state()->close())
}
I have a little problem here, sorry if asking a dumb question.
so, I have StoreCategories Class which have :
class StoreCategories
{
private $store_category_id;
private $category;
public function setStoreCategoryId($store_category_id)
{
$this->store_category_id = $store_category_id;
}
public function getStoreCategoryId()
{
return $this->store_category_id;
}
public function setCategory($category)
{
$this->category = $category;
}
public function getCategory()
{
return $this->category;
}
}
In my index.php I declare the object like this :
$types = array();
while($stmt->fetch())
{
$type = new StoreCategories();
$type->setCardId($card_id);
$type->setStoreCategoryId($store_category_id);
$type->setCategory($category);
array_push($types, $type);
}
As you see, I want to set Card ID which is not in the StoreCategories Class..
I have a Card Class like this :
class Card
{
private $card_id;
public function setCardId($card_id)
{
$this->card_id = $card_id;
}
public function getCardId()
{
return $this->card_id;
}
}
I know I can user Class Card extends StoreCategories to get the Card ID, but it's too much risk..
Anyone have the other ways to do it ?
Thanks :)
You can use Traits
Move common part of the code into new trait:
trait CardIdTrait {
private $card_id;
public function setCardId($card_id)
{
$this->card_id = $card_id;
}
public function getCardId()
{
return $this->card_id;
}
}
And modify Card class to:
class Card {
use CardIdTrait;
}
and
class StoreCategories
{
use CardIdTrait;
private $store_category_id;
private $category;
// ...
}
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.
I need to implement the following pattern in php:
class EventSubscriber
{
private $userCode;
public function __construct(&$userCode) { $this->userCode = &$userCode; }
public function Subscribe($eventHandler) { $userCode[] = $eventHandler; }
}
class Event
{
private $subscriber;
private $userCode = array();
public function __construct()
{
$this->subscriber = new Subscriber($this->userCode)
}
public function Subscriber() { return $this->subscriber; }
public function Fire()
{
foreach ($this->userCode as $eventHandler)
{
/* Here i need to execute $eventHandler */
}
}
}
class Button
{
private $eventClick;
public function __construct() { $this->eventClick = new Event(); }
public function EventClick() { return $this->eventClick->Subscriber(); }
public function Render()
{
if (/* Button was clicked */) $this->eventClick->Fire();
return '<input type="button" />';
}
}
class Page
{
private $button;
// THIS IS PRIVATE CLASS MEMBER !!!
private function ButtonClickedHandler($sender, $eventArgs)
{
echo "button was clicked";
}
public function __construct()
{
$this->button = new Button();
$this->button->EventClick()->Subscribe(array($this, 'ButtonClickedHandler'));
}
...
}
what is the correct way to do so.
P.S.
I was using call_user_func for that purpose and believe it or not it was able to call private class members, but after few weeks of development i've found that it stopped working. Was it a bug in my code or was it some something else that made me think that 'call_user_func' is able call private class functions, I don't know, but now I'm looking for a simple, fast and elegant method of safely calling one's private class member from other class. I'm looking to closures right now, but have problems with '$this' inside closure...
Callbacks in PHP aren't like callbacks in most other languages. Typical languages represent callbacks as pointers, whereas PHP represents them as strings. There's no "magic" between the string or array() syntax and the call. call_user_func(array($obj, 'str')) is syntactically the same as $obj->str(). If str is private, the call will fail.
You should simply make your event handler public. This has valid semantic meaning, i.e., "intended to be called from outside my class."
This implementation choice has other interesting side effects, for example:
class Food {
static function getCallback() {
return 'self::func';
}
static function func() {}
static function go() {
call_user_func(self::getCallback()); // Calls the intended function
}
}
class Barf {
static function go() {
call_user_func(Food::getCallback()); // 'self' is interpreted as 'Barf', so:
} // Error -- no function 'func' in 'Barf'
}
Anyway, if someone's interested, I've found the only possible solution via ReflectionMethod. Using this method with Php 5.3.2 gives performance penalty and is 2.3 times slower than calling class member directly, and only 1.3 times slower than call_user_func method. So in my case it is absolutely acceptable. Here's the code if someone interested:
class EventArgs {
}
class EventEraser {
private $eventIndex;
private $eventErased;
private $eventHandlers;
public function __construct($eventIndex, array &$eventHandlers) {
$this->eventIndex = $eventIndex;
$this->eventHandlers = &$eventHandlers;
}
public function RemoveEventHandler() {
if (!$this->eventErased) {
unset($this->eventHandlers[$this->eventIndex]);
$this->eventErased = true;
}
}
}
class EventSubscriber {
private $eventIndex;
private $eventHandlers;
public function __construct(array &$eventHandlers) {
$this->eventIndex = 0;
$this->eventHandlers = &$eventHandlers;
}
public function AddEventHandler(EventHandler $eventHandler) {
$this->eventHandlers[$this->eventIndex++] = $eventHandler;
}
public function AddRemovableEventHandler(EventHandler $eventHandler) {
$this->eventHandlers[$this->eventIndex] = $eventHandler;
$result = new EventEraser($this->eventIndex++, $this->eventHandlers);
return $result;
}
}
class EventHandler {
private $owner;
private $method;
public function __construct($owner, $methodName) {
$this->owner = $owner;
$this->method = new \ReflectionMethod($owner, $methodName);
$this->method->setAccessible(true);
}
public function Invoke($sender, $eventArgs) {
$this->method->invoke($this->owner, $sender, $eventArgs);
}
}
class Event {
private $unlocked = true;
private $eventReceiver;
private $eventHandlers;
private $recursionAllowed = true;
public function __construct() {
$this->eventHandlers = array();
}
public function GetUnlocked() {
return $this->unlocked;
}
public function SetUnlocked($value) {
$this->unlocked = $value;
}
public function FireEventHandlers($sender, $eventArgs) {
if ($this->unlocked) {
//защита от рекурсии
if ($this->recursionAllowed) {
$this->recursionAllowed = false;
foreach ($this->eventHandlers as $eventHandler) {
$eventHandler->Invoke($sender, $eventArgs);
}
$this->recursionAllowed = true;
}
}
}
public function Subscriber() {
if ($this->eventReceiver == null) {
$this->eventReceiver = new EventSubscriber($this->eventHandlers);
}
return $this->eventReceiver;
}
}
As time passes, there are new ways of achieving this.
Currently PSR-14 is drafted to handle this use case.
So you might find any of these interesting:
https://packagist.org/?query=psr-14