after creating an inheritance it outputs NULL value - php

I want to have my inheritance but it outputs null. it was working but when I extends Patient to clinic it starts to output null. my teachers instruction was to have inheritance and I need help im still studying about this inheritance but its kind a complicated for me.
<?php
class Patient{
private $name;
private $age;
private $gender;
public function record($name, $age, $gender){
$this->name = $name;
$this->age = $age;
$this->gender = $gender;
}
public function getName(){
return $this->name;
}
public function getAge(){
return $this->age;
}
public function getGender(){
return $this->gender;
}
}
class Clinic extends Patient{
private $patients = [];
public function getPatients(){
return $this->patients;
}
public function assignPatient($name, $age, $gender){
$this->patients[] = new Patient($name, $age, $gender);
}
public function deletePatient($index){
unset($this->patients[$index]);
}
}
$clinic = new Clinic();
$clinic->assignPatient("Patrick star",18,"Male");
$clinic->assignPatient("SpongeBob Squarepants",17,"Male");
$clinic->assignPatient("Eugene Krab",28,"Male");
$clinic->deletePatient(1);
var_dump($clinic->getPatients());

A few things to change here. First, you called the function for a new patient record, but you use new Patient(). Rename the function to __construct to make it the class constructor. Now you can use new Patient(...).
Also, I think extending Patient in Clinic doesn't really make sense here, because you don't want to use the classes provided by Patient and extend them.
So remove extends Patient and your code should work now:
<?php
class Patient{
private $name;
private $age;
private $gender;
public function __construct($name, $age, $gender){
$this->name = $name;
$this->age = $age;
$this->gender = $gender;
}
public function getName(){
return $this->name;
}
public function getAge(){
return $this->age;
}
public function getGender(){
return $this->gender;
}
}
class Clinic {
private $patients = [];
public function getPatients(){
return $this->patients;
}
public function assignPatient($name, $age, $gender){
$this->patients[] = new Patient($name, $age, $gender);
}
public function deletePatient($index){
unset($this->patients[$index]);
}
}
$clinic = new Clinic();
$clinic->assignPatient("Patrick star",18,"Male");
$clinic->assignPatient("SpongeBob Squarepants",17,"Male");
$clinic->assignPatient("Eugene Krab",28,"Male");
$clinic->deletePatient(1);
print_r($clinic->getPatients());
Output:
Array
(
[0] => Patient Object
(
[name:Patient:private] => Patrick star
[age:Patient:private] => 18
[gender:Patient:private] => Male
)
[2] => Patient Object
(
[name:Patient:private] => Eugene Krab
[age:Patient:private] => 28
[gender:Patient:private] => Male
)
)
Tested on PHP 7.4 and PHP 8.0

Related

Php object array (get() method not working)

I'm trying to create an object array but I have several problems.
First I can't use $item= array() in ItemModel class function without making it global.
Second I`m getting array with some weird values back.
I`m new to programming, can someone explain me what am I doing wrong?
class ItemModel{
private $item= array();
public function setItems(){
global $item;
$test = new Bmw("test....", "BMW", 32, 1, 120);
$item[] = $test;
}
public function getItems(){
global $item;
return $item;
}
}
abstract class Car{
private $id;
private $model;
private $price;
private $carTypeId;
public function __construct($id, $model, $price, $carTypeId){
$this->$id= $id;
$this->$model= $model;
$this->$price = $price;
$this->$carTypeId = $carTypeId;
}
public abstract function getAdditionalInfo();
public function getId(){
return $this->$id;
}
public function getmMdel(){
return $this->$model;
}
}
class Bmw extends Car{
private $weight;
public function __construct($id, $model, $price, $carTypeId, $weight) {
parent::__construct($id, $model, $price, $carTypeId);
$this->$weight= $weight;
}
public function getAdditionalInfo(){
return "Weight: ".$this->$weight;
}
}
class ItemView extends ItemModel{
public function showItems(){
$this->setItems();
foreach ($this->getItems() as $item) {
print_r($item);
}
die;
}
}
$test = new ItemView();
$test->showItems();
Results:
Bmw Object
(
[weight:Bmw:private] =>
[id:Car:private] =>
[model:Car:private] =>
[price:Car:private] =>
[carTypeId:Car:private] =>
[test....] => test....
[BMW] => BMW
[32] => 32
[1] => 1
[120] => 120
)
When I try to use function getId() by changing
foreach ($this->getItems() as $item) {
print_r($item->getId());
}
I get
PHP Warning: Undefined variable $id in /workspace/Main.php on line 43
PHP Warning: Undefined property: Bmw::$ in /workspace/Main.php on line 43
I did try to refactor your code and add some comments what I changed and why.
You already did some great work. I think your problem was to use global and not really knowing the syntax of php classes.
<?php
// I did remove the ItemModel Class because it looks like this should be your main code
// see at the end how we add an item from the main code
abstract class Car {
private $id;
private $model;
private $price;
private $carTypeId;
public function __construct($id, $model, $price, $carTypeId){
// when u want to access properties, you dont need specify the property with the dollar sign
$this->id = $id;
$this->model = $model;
$this->price = $price;
$this->carTypeId = $carTypeId;
}
public abstract function getAdditionalInfo();
public function getId(){
return $this->id;
}
public function getModel(){
return $this->model;
}
}
class Bmw extends Car {
private $weight;
public function __construct($id, $model, $price, $carTypeId, $weight) {
parent::__construct($id, $model, $price, $carTypeId);
$this->weight = $weight;
}
public function getAdditionalInfo(){
return "Weight: ".$this->weight;
}
}
// your ItemView class ist just a handler to store multiple items and get them back
// you also dont need to use global $item here, because you want to access the property of the current object
// when you have multiple ItemView objects it would really bug "hungry" :)
class ItemView {
private $items = array();
public function addItem($item){
$this->items[] = $item;
}
public function getItems(){
return $this->items;
}
}
// at the end it is just your items been stored in ItemView and then later getting accessed
$test = new ItemView();
$test->addItem(new Bmw("test....", "BMW", 32, 1, 120));
foreach($test->getItems() as $item) {
print_r($item);
}
// die for whatever reason
die();
You can find and run code here
<?php
class ItemModel{
private $item = array();
public function setItems($item){
$this->item[] = $item;
}
public function getItems(){
return $this->item;
}
public function getItemsAsArray(){
$arrayitem = array();
$arrayitems = array();
foreach ($this->item as $item) {
$arrayitem['ID'] = $item->getId();
$arrayitem['Model'] = $item->getModel();
$arrayitem['Price'] = $item->getPrice();
$arrayitem['TypeID'] = $item->getcarTypeId();
$arrayitem['Info'] = $item->getAdditionalInfo();
$arrayitems[] = $arrayitem;
}
return $arrayitems;
}
}
abstract class Car{
private $id;
private $model;
private $price;
private $carTypeId;
public function __construct($id, $model, $price, $carTypeId){
$this->id = $id;
$this->model = $model;
$this->price = $price;
$this->carTypeId = $carTypeId;
}
public abstract function getAdditionalInfo();
public function getId(){
return $this->id;
}
public function getModel(){
return $this->model;
}
public function getPrice(){
return $this->price;
}
public function getcarTypeId(){
return $this->carTypeId;
}
}
class Bmw extends Car{
private $weight;
public function __construct($id, $model, $price, $carTypeId, $weight) {
parent::__construct($id, $model, $price, $carTypeId);
$this->weight = $weight;
}
public function getAdditionalInfo(){
return $this->weight;
}
}
class ItemView extends ItemModel{
public function showItems(){
$this->setItems(new Bmw("test....", "BMW", 32, 1, 120));
$this->setItems(new Bmw("another....", "Z6", 16, 2, 10));
print_r($this->getItems()); //return BMW Object
// you can use somthing like this with BMW Object
print_r($this->getItems()[0]->getAdditionalInfo()."\n");
//or use my function
print_r($this->getItemsAsArray());
// or
foreach($this->getItemsAsArray() as $getItemsAsArray) {
foreach($getItemsAsArray as $key => $value) {
print_r($key."=".$value."\n");
}
}
}
}
$test = new ItemView();
$test->showItems();
?>

Get Class reference from a member object

I am trying to build some classes for a project and I was wondering how to achieve the following. I am not really sure how to ask this with words but I will provide an example:
class Table{
private $name;
private $fields = [];
public function addField(Field $field){
$this->fields[$field->getName()] = $field;
}
public function getName(){
return $this->name;
}
}
class Field{
private $name;
public function getName(){
return $this->name;
}
public function getTableName(){
//return Table::getName
}
public function getTable(){
//return a ref to the Table object
}
}
$table = new Table();
$field = new Field();
$table->addField($field);
What I am trying to achieve here, once the $field is added to the $table, is there some sort of way to get the reference of the $table from any of the methods in the $field object
I would greatly appreciate any help or ideas how to restructure it so I can achieve my goal
Thank you in advance
class Table{
private $name;
private $fields = [];
public function addField(Field $field){
$this->field->setTable($this);
$this->fields[$field->getName()] = $field;
}
public function getName(){
return $this->name;
}
}
class Field{
private $name;
private $relatedTable;
public function getName(){
return $this->name;
}
public function setName($name){
$this->name = $name;
}
public function getTableName(){
return $this->relatedTable->getName();
}
public function getTable(){
return $this->relatedTable;
}
public function setTable(Table $table){
$this->relatedTable = $table;
}
}
$field = new Field;
$field->setName('Field1');
$table = new Table;
$table->addField($field);
echo $field->getTable()->getName();
Although you have to be aware that when you pass an object to a function, it will be passed by "reference" (I know there's another term for this.)
// in case you're running it in a for loop
$field = new Field;
$table = new Table;
for($i = 0; $i < 3; $i++)
{
$field->setName("Field{$i}");
$table->addField(clone $field); // notice the clone there.
}
I think this approach is kind of similar with Observer Pattern

how to create default value for for an object? PHP

let's say I have a Human class which has the variable of $gender which doesn't have any value assigned into it. Human has a constructor with the parameter of age, gender, height and weight.
I have another class called Female which inheritance from Human but now the Female class is overriding the $gender variable with a string of Female.
When I create the object let's say $f = new Female(12, 'female', 123, 40);
How can I skip typing the female when creating the object?
I thought we need to create another new constructor in Female class which I did and in the Female class constructor's parameter I have age, gender = 'female', height and weight but this doesn't seem to work.
I tried leaving the gender part empty when creating the object or tried entering empty string such as "".
Can someone give me a hand please? Thanks a lot.
Code for my human class
class Human {
protected $age = 0;
protected $gender;
protected $height_in_cm;
protected $weight_in_kg;
function __construct($age, $gender, $heightCM, $weightKG)
{
$this->age = $age;
$this->gender = $gender;
$this->height_in_cm = $heightCM;
$this->weight_in_kg = $weightKG;
}
/**
* #return int
*/
public function getAge()
{
return $this->age;
}
/**
* #return string
*/
public function getGender()
{
return $this->gender;
}
}
Code for Female class
require_once('Human.php');
class Female extends Human{
protected $gender = 'female';
function __construct($age, $gender = 'female', $heightCM, $weightKG)
{
$this->age = $age;
$this->gender = $gender;
$this->height_in_cm = $heightCM;
$this->weight_in_kg = $weightKG;
}
}
$f = new Female(12,'female',123,40);
echo "Your gender is ". $f->getGender()."<br>";
Simply override the constructor:
class Human {
public function __construct($age, $gender, $height, $weight) {
}
}
class Female extends Human {
public function __construct($age, $height, $weight) {
parent::__construct($age, 'Female', $height, $weight);
}
}
You can just set the value in the extended class:
// If it should be possible to instantiate the Human
// class then remove the "abstract" thing at set the
// "gender" property in the constructer
abstract class Human {
protected $gender;
protected $age;
public function __construct($age) {
$this->age = $age;
}
}
class Female extends Human {
protected $gender = "Female";
}
class Male extends Human {
protected $gender = "Male";
}
Although this works, it really does not make that much sense. The class itself tells you what gender the human is, so you can just call $human instanceof Female.
$person = new Female(18);
if ($person instanceof Female) {
echo "Person is female";
}
You can simply overwrite the constructor:
abstract class Human
{
protected $age;
protected $gender;
protected $height;
protected $weight;
public function __construct($age, $gender, $height, $weight)
{
$this->age = $age;
$this->gender = $gender;
$this->height = $height;
$this->weight = $weight;
}
public function getGender()
{
return $this->gender;
}
}
class Female extends Human
{
public function __construct($age, $height, $weight)
{
parent::__construct($age, 'female', $height, $weight);
}
}
$female = new Female(12, 170, 60);
echo $female->getGender();
I think, in you constructor
__construct($var, $gender="female", $var, $var){
//rest assignment
}
should do it
alternatively, use 3 param constructor with female already set

understanding dependency injection in PHP

class Author {
private $firstName;
private $lastName;
public function __construct($firstName, $lastName) {
$this->firstName = $firstName;
$this->lastName = $lastName;
}
public function getFirstName() {
return $this->firstName;
}
public function getLastName() {
return $this->lastName;
}
}
class Question {
private $author;
private $question;
public function __construct($question, Author $author) {
$this->author = $author;
$this->question = $question;
}
public function getAuthor() {
return $this->author;
}
public function getQuestion() {
return $this->question;
}
}
Class author is injected into the constructor of Question class am I correct? but how to call the Question class to get the author's name?
$question = new Question('What is PHP', 'Adam');
$question->getFirstname;
like this? I assume Question class inherited Author class so Question's instance can use the function of Author Class?
Simple
echo $question->getAuthor()->getFirstName();
Think of it this way if it helps
$author = $question->getAuthor();
echo $author->getFirstName();
Also note that you can't construct a Question with the string "Adam", you need to pass an instance of Author
$question = new Question('What is PHP', new Author('Adam', 'Lastname'));
You could create a new method:
class Question
{
// ...
function getAuthorFirstname()
{
return $this->author->getFirstname();
}
}
$question = new Question(.., new Author(..., ...));
echo $question->getAuthorFirstname();
Or, if you don't really care about Law of Demeter or feel that it doesn't apply:
$question = new Question(.., new Author(..., ...));
echo $question->getAuthor()->getFirstname();
In the end it all comes down to striking a balance between information hiding and pragmatism.

Get data from object composition

Let's say I have 3 objects : "Place", "Person", "Action".
Depending on the place where is the person and the age of this person, this person can do different action.
For example :
$place->person->action->drive(); // OK if place is "parking" and "person" is 18+
$place->person->action->learn(); // OK if the place is "school" and person is less than 18.
How can I access the data about the objects "Person" and "Place" from the Action class ?
Classes examples :
class Place {
public $person;
private $name;
function __construct($place, $person) {
$this->name = $place;
$this->person = $person;
}
}
class Person {
public $action;
private $name;
private $age;
function __construct($name, $age) {
$this->name = $name;
$this->age = $age;
$this->action = new Action();
}
}
class Action {
public function drive() {
// How can I access the person's Age ?
// How can I acess the place Name ?
}
public function learn() {
// ... Same problem.
}
}
I think I could transmit "$this" from Person to Action when I create the Action Object (ie. $this->action = new Action($this)), but what about the Place data ?
It doesn't make sense to make Person a property of Place nor Action a property of Person.
I'd be more inclined to create public getters for Person and Place's properties and either make them injectable properties of Action or at least pass them as arguments to Action's methods, eg
class Place
{
private $name;
public function __construct($name)
{
$this->name = $name;
}
public function getName()
{
return $this->name;
}
}
class Person
{
private $name;
private $age;
public function __construct($name, $age)
{
$this->name = $name;
$this->age = $age;
}
public function getName()
{
return $this->name;
}
public function getAge()
{
return $this->age();
}
}
class Action
{
private $person;
private $place;
public function __constuct(Person $person, Place $place)
{
$this->person = $person;
$this->place = $place;
}
public function drive()
{
if ($this->person->getAge() < 18) {
throw new Exception('Too young to drive!');
}
if ($this->place->getName() != 'parking') {
throw new Exception("Not parking, can't drive!");
}
// start driving
}
}

Categories