I'm sorry for what is probably an easy question, but I'm having trouble finding anything about it on the web. I have two classes, for the purposes of this post let's call them user and address, looking like this:
class user {
public $firstName;
public $lastName;
public $address;
}
class address{
public $streetAddress;
public $streetName;
public $city;
public $state;
public $zip;
}
In this case, I want the $address parameter in the user class to be of type "address" defined by the second class. Can I do this in PHP? My end goal is to be able to consume properties like this:
$userZip = $user->address->zip;
Am I on the right track or way off?
Try like this;
<?php
class user {
public $firstName='bulent';
public $lastName ='kocaman';
public $address;
public function __construct()
{
$this->address = new address();
}
}
class address{
public $streetAddress=1;
public $streetName=2;
public $city=3;
public $state=4;
public $zip=5;
}
$user = new user();
print_r($user->address->zip);
?>
or
<?php
class user extends address{
public $firstName='bulent';
public $lastName ='kocaman';
}
class address{
public $streetAddress=1;
public $streetName=2;
public $city=3;
public $state=4;
public $zip=5;
}
$user = new user();
print_r($user->zip);
?>
$address = new $address();
I believe this is what you're looking for.
In PHP variable types are defined by the data they are assigned to. If you want $address in class 1 to be of type $address (class 2) then all you have to do is assign it to an instance of $address and it will take on that type. You will then be able to access any of the $address properties by using:
$user->address->zip
In short, yes you are on the right track. Look into adding constructors to your classes.
Related
I am experimenting with php class inheritance, I wrote the below code and got an uncaught error that the User class is not found. Please any help about where am going wrong will be fine.
the first block is the User class
<?php
class User{
private $name;
private $age;
public function _construct($name, $age){
$this->name = $name;
$this->age = $age;
}
}
?>
below is the customer class that inherit the user class.
<?php
class Customer extends User{
private $balance;
public function __construct($name, $age, $balace) {
parent::_construct($name, $age);
$this->balance = $balace;
}
public function pay($amount){
return $this->name ." paid $".$amount;
}
public function getBalance(){
return $this->balance;
}
}
$customer = new Customer("Matt", 23, 500);
echo $customer->getBalance();
I have checked your code by implementing it in a single file. It works fine.
If you are having 2 files for both classes, you need to include the User class file into the Customer class file like below.
require_once('User.php');
i want to show a name.name may be in uppercase or in lowercase this will be depend on which class i will pass.i have to approach one is using class and second is interface which one is better and why ?
Solution using Class
class User{
}
class Iuser extends User{
private $name;
function __construct($name){
$this->name = $name;
}
function getName(){
return strtoupper($this->name);
}
}
class Wuser extends User{
private $name;
function __construct($name){
$this->name = $name;
}
function getName(){
return strtolower($this->name);
}
}
class Name{
public $u;
function __construct(User $u){
$this->u = $u;
}
function getName(){
$name = $this->u->getName();
return "Hi My Name is ".$name;
}
}
$name = "Deval Patel";
$iu = new Iuser($name);
$wu = new Wuser($name);
$user = new Name($wu);
echo $user->getName();
Solution Using Interface
interface User{
public function getName();
}
class Iuser implements User{
private $name;
function __construct($name){
$this->name = $name;
}
function getName(){
return strtoupper($this->name);
}
}
class Wuser implements User{
private $name;
function __construct($name){
$this->name = $name;
}
function getName(){
return strtolower($this->name);
}
}
class Name{
public $u;
function __construct(User $u){
$this->u = $u;
}
function getName(){
$name = $this->u->getName();
return "Hi My Name is ".$name;
}
}
$name = "Deval Patel";
$iu = new Iuser($name);
$wu = new Wuser($name);
$user = new Name($iu);
echo $user->getName();
Using the interface solution the getName() method is defined but not implemented in User interface (not shown in your code), so each class implementing it has to define the behaviour to get the name, whilst using abstract classes you may define the standard way to get the name, and override or overload the method in child classes when necessary.
So for your code, I think the best solution is the abstraction.
Remember to use interfaces when you want to force the developer to code the getName() method, and for abstract classes just to allow the developer to use the parent method getName(), or override/overload if necessary. Interfaces gives you more control and code reutilization.
Review the PHP object interfaces doc and PHP class abstraction doc, it may shed some light on your doubt.
I would use classes because you can reuse some code.
abstract class User
{
protected
$name;
public function __construct($name)
{
$this->name = $name;
}
abstract function getName();
}
class Iuser extends User
{
public function getName()
{
return strtoupper($this->name);
}
}
class Wuser extends User
{
function getName(){
return strtolower($this->name);
}
}
This way you can still use polymorphism and reuse some common code.
It's better then interface because the code reuse. You can still use an interface for the abstract class User but I think it would be an overkill.
I have been doing some research on objects in PHP. All the examples I have seen use the object constructor even on their own objects. Does PHP force you to do this and if so why?
For example:
<?php
class Person {
public $isAlive = true;
public $firstname;
public $lastname;
public $age;
public function __construct($firstname, $lastname, $age) {
$this->firstname = $firstname;
$this->lastname = $lastname;
$this->age = $age;
}
public function greet() {
return "Hello, my name is " . $this->firstname . " " . $this->lastname . ". Nice to meet you! :-)";
}
}
// Creating a new person called "boring 12345", who is 12345 years old ;-)
$me = new Person('boring', '12345', 12345);
echo $me->greet();
?>
But if I do this:
<?php
class Person {
public $isAlive = true;
public $firstname;
public $lastname;
public $age;
}
$person->firstname = "John";
echo $person->firstname;
?>
I get a http error code 500.(ie: My code crashed).
You're incorrectly associating the __construct() function with the way in which you instantiate a class/object.
You don't have to use the __construct() function (it's optional). However, before you can use a class's methods, you do have to create an instance of it first.
<?php
class Person {
public $isAlive = true;
public $firstname;
public $lastname;
public $age;
}
$person = new Person(); //Add this line
$person->firstname = "John";
echo $person->firstname;
?>
Because a class definition is exactly that, a definition.
To create an instance of a class (an actual object), you have to instantiate it. You may in fact instantiate many different objects/instances of the same class.
And you don't have to define a constructor method..... but you do have to instantiate using new
There are two ways to work with the class variables.
1. the variable should be public static like:
class Person {
public $isAlive = true;
public static $firstname;
public $lastname;
public $age;
}
Person::$firstname = "John";
echo Person::$firstname;
2. the access to variable via the class object
class Person {
public $isAlive = true;
public $firstname;
public $lastname;
public $age;
}
$person->firstname = "John";
echo $person->firstname;
By the way, PHP can create the object by itself php 5.5 at least.
Your code is not crashing. It just gives a Warning:
Warning: Creating default object from empty value in ...
So WHY?
This is how PHP working with the memory. In a first case the static means that php already allocated memory for the variable and you can work with it. The second case. By using NEW command you give instruction to php to allocate memory and load class into it. So, after the class was created you have an access to the var.
In a third case PHP is calling new Person by itself and give you the warning. I am strongly not recommend to count on php default behavior. ALWAYS create an object in explicit way
I am following a tutorial on dependency injection. My issue is that I do not understand how some of the variables are being formulated within the classes. Within class Author we have $firstname and $lastname. Within class Question we have $author and $question. Then magically(?) we have within the class Question constructor we get $authorFirstname and $authorLastname.
I don't get it - it's like they have been concatenated, but that can't be, right ?? But then the $authorFirstname and $authorLastname have not been declared within class Question.
So, Question: how does the author get to the $authorFirstname and $authorLastname - or am I over thinking this ??
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, $authorFirstName, $authorLastName) {
$this->author = new Author($authorFirstName, $authorLastName);
$this->question = $question;
}
public function getAuthor() {
return $this->author;
}
public function getQuestion() {
return $this->question;
}
}
You're overthinking.
you notice, __construct($question, $authorFirstName, $authorLastName)...
construct is a special function that runs when a new object of that class is created.
$authorFirstName and $authorLastName are just variables to be passed to the Question constructor function, aka
$question = new Question($questioninfo,'William','Shakespeare');
(in this case, $authorFirstName = William, $authorLastName = Shakespeare)
They only get used within the scope of the __construct() function, which in this case instantiates a new Author. so if the input was as above, this will happen inside the constructor of Question:
$this->author = new Author('William', 'Shakespeare');
and those variables will be handled by Author's constructor, as $firstName and $lastName... make sense?
The Question ctor is an example of a hidden dependency, not showing how dependency injection works:
public function __construct($question, $authorFirstName, $authorLastName) {
$this->author = new Author($authorFirstName, $authorLastName);
$this->question = $question;
}
As this code shows, the parameters $authorFirstName, $authorLastName are used to create the Author dependcy inside Question. Therefore the dependency is not injected.
Instead, the author should be injected:
public function __construct($question, Author $author) {
$this->author = $author;
$this->question = $question;
}
The Question is only interested in compositing an Author, there is no need that the Question needs to create an Author.
I hope this also illustrates how parameters work.
This is what I have: All objects that can be persisted on the database extend the DatabaseObject abstract class, which has all the logic code to actually watch for attribute changes and run the databas queries.
I'm using two static variables to define object-specific details. I define them generically in the base class, and then supposedly I overwrite them in the actual database objects.
The problem is: When the code in the parent class is actually executed, it uses the old parent value instead of the current object value.
Here's the code for the base class:
abstract class DatabaseObject {
public $id;
private static $databaseTable = NULL;
private static $databaseFields = array();
private $data = array();
private $changedFields = array();
public function IDatabaseObject($id) {
$this->id = $id;
$this->data = Database::GetSingle(self::$databaseTable, $id);
Utils::copyToObject($this, $this->data, self::$databaseFields);
}
public static function Load($id) {
return new self($userID);
}
public static function Create($data) {
$id = Database::Insert(self::$databaseTable, $data);
return new self($id);
}
public function Save() {
$data = Utils::copyFromObject($this, $this->changedFields);
Database::Update(self::$databaseTable, $data, $this->id);
}
public function __constructor() {
// We do this to allow __get and __set to be called on public vars
foreach(self::$databaseFields as $field) {
unset($this->$field);
}
}
public function __get($variableName) {
return $this->$variableName;
}
public function __set($variableName, $variableValue) {
// We only want to update what has been changed
if(!in_array($variableName, $this->changedFields) && in_array($variableName, self::$databaseFields)) {
array_push($this->changedFields, $variableName);
}
$this->$variableName = $variableValue;
}
}
And here's the code for one of the objects extending the base class above:
class Client extends DatabaseObject {
public static $databaseTable = "clients";
public static $databaseFields = array("name","contactName","primaryUserID","email","is_active","rg","cpf","cnpj","ie","addrType","addrName","addrNumber","addrComplement","addrPostalCode","addrNeighborhood","addrCity","addrState","addrCountry","phoneLandline","phoneFax","phoneMobile");
public $name;
public $contactName;
public $primaryUserID;
public $email;
public $is_active;
public $rg;
public $cpf;
public $cnpj;
public $ie;
public $addrType;
public $addrName;
public $addrNumber;
public $addrComplement;
public $addrPostalCode;
public $addrNeighborhood;
public $addrCity;
public $addrState;
public $addrCountry;
public $phoneLandline;
public $phoneFax;
public $phoneMobile;
public static function Load($id) {
return new Client($id);
}
}
What am I doing wrong here? Is there another way I can achieve the same result?
A brief addendum: I declare the attributes in the class body mainly to let it be seen by the NetBeans' auto-complete feature.
You are looking for Late Static Binding.
So you need to use:
static::$databaseTable
instead of
self::$databaseTable
This feature is available as of PHP 5.3. Simulating this in PHP 5.2 is very hard, because of two reasons: get_called_class is available only since PHP 5.3, too. Therefore it must be simulated, too, using debug_backtrace. The second problem is, that if you have the called class, you still may not use $calledClass::$property because this is a PHP 5.3 feature, too. Here you need to use eval or Reflection. So I do hope that you have PHP 5.3 ;)