I am trying to learn simple method of php oop by calling parent function data in child.
However somewhere I am making mistake.
class name{
var $firstname;
var $lastname;
var $name;
public function name($firstname, $lastname){
$this->firstname=$firstname;
$this->lastname=$lastname;
$this->name=$this->firstname." ".$this->lastname;
return $this->name;
}
}
class sentence extends name{
var $name;
var $letter;
function sentence(){
$this->letter="My name is ";
echo $this->letter.$this->name;
}
}
$name=new name(ABC, Xyz);
$letter=new sentence();
I have created one calls to get name input and another child class to write the sentence. However not able to call the name in child.
a quick fix since thats probably what you want.
<?php
class name {
private $firstname;
private $lastname;
private $name;
private $sentence;
public function __construct($firstname, $lastname){
$this->firstname = $firstname;
$this->lastname = $lastname;
$this->name = $firstname . " " . $lastname;
$this->sentence = "My name is : " . $this->name;
}
public function getName(){
return $this->name;
}
public function getSentence(){
return $this->sentence;
}
}
$instance = new name("test","lastname");
echo $instance->getSentence();
?>
class name
{
public $firstname;
public $lastname;
public $name;
public function name($firstname, $lastname)
{
$this->firstname = $firstname;
$this->lastname = $lastname;
$this->name = $this->firstname.' '.$this->lastname;
return $this->name;
}
}
class sentence extends name
{
public $name;
public $letter;
public function greeting()
{
$this->letter = 'My name is ';
echo $this->letter.$this->name;
}
}
//$name=new name(ABC, Xyz);
$letter = new sentence('ABC', 'Xyz');
$letter->greeting();
Thanks to #ManhNguyen
Are you trying to read the state of variables in a parent class?
That is not how OOP works.
You have to either group together all the variables into one class or pass it trough as an argument to the function you want to have access to the data.
Second of all you don't seem to not be using a __construct function and yet pass variables into the new name() function that is also a NO-NO.
Related
I'm having difficulties to understand the given code and the reason behind dependency injection. I've got the following error:
Uncaught Error: Call to undefined method Question::getFullName() in C:\xampp\htdocs\OOP\Index.php:10 Stack trace: #0 {main} thrown in C:\xampp\htdocs\OOP\Index.php on line 10.
Even if I instantiate an object of the Author class in the constructor, I keep getting a string in the Question class once I try to use getQuestion().
require 'Author.php';
class Question {
private $author;
private $question;
public function __construct($question, Author $author) {
$this->author = $author;
$this->question = $question;
}
public function getAuthor() {
$firstname = $this->author->getFirstName();
$lastname = $this->author->getLastName();
$fullaname = $firstname . $lastname;
return $this;
}
public function getQuestion() {
return $this->question;
}
}
<?php
class Author {
private $firstName;
private $lastName;
private $fullName;
public function __construct($firstName, $lastName) {
$this->firstName = $firstName;
$this->lastName = $lastName;
}
public function getFirstName() {
return $this->firstName;
}
public function getLastName() {
return $this->lastName;
}
public function getFullName() {
return $this->fullName = $this->firstName." ".$this->lastName;
}
}
require 'Question.php';
$question = new Question("What is the author's name?", new Author("josel", "parayno"));
echo $question->getQuestion();
echo $question->getFullName();
$question really does not have getFullName method. Method getFullName exists in class Author. And after creating and "sending" to Question, when it was created method getFullName available in class Question private $author property.
But if you want to get Athor name by follow code, you need try
$question->getAuthor()->getFullName();
And if you do this, you take error again, becouse in question->getAuthor you return $this, and in this case this is a Question object. For getting author name from question object you should to do follow:
Fix getAuthor like this
public function getAuthor()
{
$firstname = $this->author->getFirstName();
$lastname = $this->author->getLastName();
return $this->author;
}
Rewite call name in you index.php like this
echo $question->getAuthor()->getFullName();
class userDetails {
private $usersEmail;
private $firstName;
private $lastName;
// check if it's returned
// echo $usersEmail.' '.$firstName.' '.$lastName;
//setter for class properties
public function __constructor($email,$fname,$lname) {
$this->usersEmail = $email;
$this->firstName = $fname;
$this->lastName = $lname;
}
//getter for class properties
function getPropertyEmail() {
return $this->usersEmail;
}
function getPropertyFName() {
return ($this->firstName);
}
function getPropertyLName() {
return ($this->lastName);
}
}
$something = "something";
//$something is actually a $_GET['id']; sent from xhrobject
$createdUser = new userDetails($something,$something,$something);
echo $createdUser->getPropertyEmail();
Please use __construct() method instead __constructor()
Try this :
class userDetails {
private $usersEmail;
private $firstName;
private $lastName;
// check if it's returned
// echo $usersEmail.' '.$firstName.' '.$lastName;
//setter for class properties
public function __construct($email,$fname,$lname) {
$this->usersEmail = $email;
$this->firstName = $fname;
$this->lastName = $lname;
}
//getter for class properties
function getPropertyEmail() {
return $this->usersEmail;
}
function getPropertyFName() {
return ($this->firstName);
}
function getPropertyLName() {
return ($this->lastName);
}
}
$something = "something";
//$something is actually a $_GET['id']; sent from xhrobject
$createdUser = new userDetails($something,$something,$something);
echo $createdUser->getPropertyEmail();
I need different __toString() for the same class.
Example
I have the Person class that contains a firstname and a surname. According to current context I wish to display it with different order, formatting etc. Imagine three scenarios:
the firstname comes first, followed by space and surname Thomas Müller
the surname comes first and uppercased, followed by space and the firstname MÜLLER Thomas
the surname comes first, followed by comma, then space and the firstname Müller, Thomas
I can create public methods for each display.
<meta charset='utf-8'/>
<?php
class Person
{
protected $firstname;
protected $surname;
public function __construct($firstname, $surname)
{
$this->firstname = $firstname;
$this->surname = $surname;
}
public function toStringWithFirstnameFirst()
{
return $this->firstname . " " . $this->surname;
}
public function toStringWithSurnameFirstUppercase()
{
$surnameConverted = mb_convert_case($this->surname, MB_CASE_UPPER, "UTF-8");
return $surnameConverted . " " . $this->firstname;
}
public function toStringWithSurnameFirstAndFirstnameAfterComma()
{
return $this->surname . ", " . $this->firstname;
}
}
$person = new Person("Thomas", "Müller");
echo $person->toStringWithFirstnameFirst() . "<br/>";
echo $person->toStringWithSurnameFirstUppercase() . "<br/>";
echo $person->toStringWithSurnameFirstAndFirstnameAfterComma() . "<br/>";
?>
But I stuck with DescriptiveButVeryLongToStringMethodNames.
I wish to have simply echo $person; in the code.
Solution: store the class state in the static members
My first solution is to place switch-case inside __toString() method. Conditional statement depends on the class state stored in the static variable self::$chosenToStringMethod. So I need static method to set the class state and also class constants that serve as enums.
<meta charset='utf-8'/>
<?php
class Person
{
protected $firstname;
protected $surname;
const PRINT_FIRSTNAME_FIRST = 1;
const PRINT_SURNAME_FIRST_UPPERCASE = 2;
const PRINT_SURNAME_FIRST_FIRSTNAME_AFTER_COMMA = 3;
static private $chosenToStringMethod;
public function __construct($firstname, $surname)
{
$this->firstname = $firstname;
$this->surname = $surname;
}
static public function setToStringMethod($choice)
{
self::$chosenToStringMethod = $choice;
}
private function toStringWithFirstnameFirst()
{
return $this->firstname . " " . $this->surname;
}
private function toStringWithSurnameFirstUppercase()
{
$surnameConverted = mb_convert_case($this->surname, MB_CASE_UPPER, "UTF-8");
return $surnameConverted . " " . $this->firstname;
}
private function toStringWithSurnameFirstAndFirstnameAfterComma()
{
return $this->surname . ", " . $this->firstname;
}
public function __toString()
{
switch (self::$chosenToStringMethod) {
case self::PRINT_FIRSTNAME_FIRST:
return $this->toStringWithFirstnameFirst();
break;
case self::PRINT_SURNAME_FIRST_UPPERCASE:
return $this->toStringWithSurnameFirstUppercase();
break;
case self::PRINT_SURNAME_FIRST_FIRSTNAME_AFTER_COMMA:
return $this->toStringWithSurnameFirstAndFirstnameAfterComma();
break;
default:
return "No __toString method set";
break;
}
}
}
$person = new Person("Thomas", "Müller");
echo $person . "<br/>";
Person::setToStringMethod(Person::PRINT_FIRSTNAME_FIRST);
echo $person . "<br/>";
Person::setToStringMethod(Person::PRINT_SURNAME_FIRST_UPPERCASE);
echo $person . "<br/>";
Person::setToStringMethod(Person::PRINT_SURNAME_FIRST_FIRSTNAME_AFTER_COMMA);
echo $person . "<br/>";
?>
I see some disadvantages of this solution:
Person class is getting heavy
switch-case statements can hide some mistakes
I wish Person class containing only its own functionality not all kinds of toStrings. I would rather have some pattern that can dynamically inject __toString().
ok, I assume the reason, why you're asking, is that you'd like to keep things clean but there's no way to set __toString() method to an existing object, so the best solution would be to split functionality
first create a PersonRender:
class PersonRender
{
const PRINT_FIRSTNAME_FIRST = 1;
const PRINT_SURNAME_FIRST_UPPERCASE = 2;
const PRINT_SURNAME_FIRST_FIRSTNAME_AFTER_COMMA = 3;
static public $chosenToStringMethod;
private $person;
public function __construct($person)
{
$this->person = $person;
}
public function render()
{
switch (self::$chosenToStringMethod)
{
case self::PRINT_SURNAME_FIRST_UPPERCASE :
return $this->toStringWithSurnameFirstUppercase();
case self::PRINT_SURNAME_FIRST_FIRSTNAME_AFTER_COMMA :
return $this->toStringWithSurnameFirstAndFirstnameAfterComma();
default :
return $this->toStringWithFirstnameFirst();
}
}
private function toStringWithFirstnameFirst()
{
return "{$this->person->firstname} {$this->person->surname}";
}
private function toStringWithSurnameFirstUppercase()
{
$surnameConverted = mb_convert_case($this->person->surname, MB_CASE_UPPER, "UTF-8");
return "{$surnameConverted} {$this->person->firstname}";
}
private function toStringWithSurnameFirstAndFirstnameAfterComma()
{
return "{$this->person->surname}, {$this->person->firstname}";
}
}
and then the Person class:
class Person
{
public $firstname, $surname;
public function __construct($firstname, $surname)
{
$this->firstname = $firstname;
$this->surname = $surname;
}
public function __toString() {
$render = new PersonRender($this);
return $render->render();
}
}
and a little test:
$person = new Person('Foo', 'Bar');
echo $person;
echo '<hr />';
PersonRender::$chosenToStringMethod = PersonRender::PRINT_SURNAME_FIRST_UPPERCASE;
echo $person;
EDIT 1
to keep the code clean, the Person entity class should of course have private props firstname and surename and methods set and get
In my opinion the most clean way would be to just provide getter for firstname and surname and manually assemble the strings where you need them. In your current solutions you are just polluting your workspace with unnecessary classes and make the class Person more complex than it should be.
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.
I have created a class Person, who contain a person. Here is my code:
<?php
class Person {
private $age;
private $firstName;
private $lastName;
private $optional;
function __construct($id) {
// Load all settings form database, because the person already exists.
}
function __construct($age, $firstName, $lastName, $optional) {
$this->age = $age;
$this->firstName = $firstName;
$this->lastName = $lastName;
$this->optional = $optional;
}
function setFirstName($name) {
$this->firstName = $name;
}
function setLastName($name) {
$this->lastName = $name;
}
function setOptional($key, $value) {
$optional[$key] = $value;
}
function setAge($age) {
$this->age = $age;
}
function getFirstName() {
return $this->firstName;
}
function getLastName() {
return $this->lastName;
}
function getOptional($key) {
return $optional[$key];
}
function getAge() {
return $this->age;
}
}
?>
First: This person will be created if a new user fill a form on the web page (and stored to database) and this person will also be used when the web app want some information about the current user.
How do I interact this class with the database? I guess that I could create two constructors as I have done (I think that you could do like this in java). The first constructor is for when constructing an already registered user, and therefore it will load all information from the database. The second constructor is for when a new user is registered, and it should send all information to the database. Is this the right way to handle the database?