Just starting out with OOP in PHP and in general. From what I have been reading so far the two seem to be synonyms. Is this the case, and if not, practically speaking when people refer to objects and classes do they generally use the terms interchangeably?
Typically one would refer to an object as an instance of a class.
So you have some class Employee.
class Employee {
var $name;
function get_name ( ) { return $this->name; }
function set_name ($new_name) { $this->name = $new_name; }
}
And you declare an instance of it like:
$assistant = new Employee();
Employee is a class. $assistant is an object, that is an instance of the Employee class.
So to answer your question - a class is not an object. You create an object when you instantiate a class.
objects and classes do they generally use the terms interchangeably?
No. As in other OOP languages, classes are like the blueprints for something, say a house. Objects are the actual house after it's built. Very different things indeed.
// blueprint
class House
{
public $color;
public function __construct($color = 'red')
{
$this->color = $color;
}
}
// make red house
$redHouse = new House();
// make blue house
$blueHouse = new House('blue');
// Now we have two different houses (objects) made from the same blueprint (class)
They're certainly not synonymous, and if you've been reading that, it's time to change the book! :-)
Classes are types, while objects are instances.
A simple example is an integer. "Integer" denotes the type, but an integer $x is an instance of that type. In PHP there isn't a strong type system, so this may not be entirely apparent, but I hope you get the idea. Similarly, array is a type, but $v = array(); creates an instance (called $v) of array type.
With classes, you cannot just say $y = MyClass(); as you do with arrays, instead, you have to use new: $y = new MyClass();.
A class is a definition of an object. An object is an instance of a class. For example:
class Parser {
public function parse() {}
}
...is a class. You might say "The Parser class can be used to parse text."
$p = new Parser;
Now, $p is an object. It is an instance of the Parser class.
This is particularly important with the static keyword. Static methods and members belong to classes, not objects.
class Parser {
public static $type;
public $text;
}
$p1 = new Parser;
$p2 = new Parser;
$p1::$type = 'php';
$p1->text = 'sometext';
$p2->text = 'someothertext';
echo $p2::$type; //echos "php"
echo $p1->text; //echos "sometext"
You can remove the in php from your question and it is still the same thing.
A class defines an Object for example
class Person {
}
is a class that defines an person object.
The distinction get more important when you start creating class methods and object methods
class Person {
function hair_color(color) {
hair_color = color;
}
}
is an object method in php you could do something like this
austin = new Person()
austin -> hair_color("brown")
now you can have something like
class Person {
total = 0;
static function total_in_class() {
total++;
}
}
now that is an class method it affects all objects of the same class
that way
austin = new Person();
austin -> total_in_class
tom = new Person();
echo tom->total
Now if my php isn't that rusty then it should echo 1. That is because all objects in the class are affected
In ruby it would look as follows
class Person
def hair_color(color)
hair_color = color;
end
def self.total_in_class()
total+=1
end
end
Similar and same concepts apply
Related
I have been looking hard for a solution on this and i can't solve it so i will ask my question here and hopefully it will help others searching for the same question.
I have a Class for an items based on "Armor" for example.
class Armor {
public $name, $defense, $durability;
function __construct($name, $defense, $durability){
$this->name = $name;
$this->defense = $defense;
$this->durability = $durability;
}
}
Then i create a bunch of objects like this:
$heavy_armor = new Armor("Heavy Armor", 250, 50);
Then in a totally different file and use, I have another class for Magic Items which will create a brand new Magic Item but the base i want to use is the already existing heavy armor. However, there is a catch. I am already extending a different MagicArmors class because i will be creating a lot of these new classes and i want the common properties that will be the same across all Magic Armors to stay in one place - the MagicArmors class. Example:
class MagicHeavyArmor extends MagicArmors {
public function __construct() {
$this->name = "Magic Heavy Armor";
// so here i want to point to the Defense and Durability of the $heavy_armor object
$this->defense = 625; // Ideally i want $this->defense = $heavy_armor->defense * 2.5
$this->durability = 87.5; // Same here - I want $this->durability = $heavy_armor->durability * 1.75
}
So how do I make this work? The reason is that i will be creating a huge load of these and i want all of them to be able to looking for their base properties from other objects. And if i need to change a value of a property, to ease my life later.
The constructor should take the previous armor as a parameter, and can refer to its properties.
public function __construct($armor) {
$this->name = "Magic " . $armor->name;
$this->defense = $armor->defense * 2;
$this->durability = $armor->durability * 1.75;
}
Then you create the object like this:
new MagicHeavyArmor($heavy_armor);
The I18n class in CakePHP provides this method to create instances:
public static function getInstance() {
static $instance = array();
if (!$instance) {
$instance[0] = new I18n();
}
return $instance[0];
}
Among other considerations (please correct me if I'm wrong), I understand it helps to use class instances from the convenience functions:
/**
* Returns a translated string if one is found; Otherwise, the submitted message.
*/
function __($singular, $args = null) {
// ...
$translated = I18n::translate($singular);
// ...
}
echo __('Hello, World!');
This looks cleaner than having to pass the instance around as argument (or, even worse, using a randomly named global variable). But I can't imagine a reason why $instance is an array rather than a plain object.
What can be the purpose of using a one-item array to store class instances?
I would suspect this to be leftovers from older PHP4/CakePHP versions where the instances were assigned by reference.
https://github.com/cakephp/cakephp/blob/1.2.0/cake/libs/i18n.php
function &getInstance() {
static $instance = array();
if (!$instance) {
$instance[0] =& new I18n();
$instance[0]->l10n =& new L10n();
}
return $instance[0];
}
$_this =& I18n::getInstance();
Assigning by reference doesn't work with static, the reference is not being remembered, but it works when assigned to an array entry.
So this was most probably just a workaround for a PHP limitation.
One possible reason for this is to keep all singleton class instances in one global - (static is a synonym of global in this case) array variable for monitoring or not messing the global/local namespace with individual variables for each singleton. If each of the static variables were with random names e.g $translated it would be more easier to overwrite and mess its value. - bug again for me, this is extremely rear possibility.
For example the I18Nn instance would be with [0] key, other class would have other key. You should check outher singleton classes how manage the static $instance array values.
I’ve tagged this question PHP, but it’s more a question on design patterns, namely the factory pattern; PHP is just the programming language I’m using.
I’m building an estate agents’ (“real estate” for American cousins) website. I have a Property class, but then other classes that extend this, i.e. LettingProperty, CommercialProperty that has fields specific to that type of property.
In my controller I want to display a particular property. This is easy as I pass the property ID as a parameter. My approach is to then create a factory class that returns the property as an instance of the relevant class. For example, if the property with an ID of 1 is a letting property, return an instance of LettingProperty. If it’s just a standard “for sale” property, an instance of Property.
How can I go about this? I created a PropertyFactory class and implemented a method called buildFromId(), but having trouble on creating an elegant solution to:
Find the relevant record in my properties database table
Do any LEFT JOINs (i.e. if it’s a letting property left join the relevant data from letting_properties (foreign key: property_id)
Return the resultant data, as an instance of the corresponding class
Is a factory approach the correct design pattern for this scenario? And if so, how could I go about the above?
If you already can produce a query that variably flattens the the tree using left joins then you can do something like this on the php side to create your object model. Of course you would want to fill out the implementation a more on the property types for them to really be useful.
class Property {
public function setPropertyValuesFromArray($array){
foreach($array as $k=>$v){
$this->$k = $v;
}
}
}
class CommercialProperty extends Property {}
class LettingProperty extends Property {}
class PropertyFactory {
protected $db;
public function __construct(DbConnection $db){
$this->db = $db;
}
public function getPropertyById($id){
$result = $this->db->fetchRow($queryToGetPropertyById);
return $this->getPropertyFromArray($result);
}
public function getPropertyFromArray($result){
switch($result["property_type"]){
case "residential":
$p = new Property();
break;
case "commericial":
$p = new CommercialProperty();
break;
case "letting":
$p = new LettingProperty();
break;
default:
throw new Exception("Unknown Property Type ".$result["property_type"]);
break;
}
$p->setPropertyValueFromArray($result);
return $p;
}
}
I'm new to oop and was surprised to see that code that worked properly in procedural programming,
<?php
$number_of_floors = 5;
$stairs_per_floor= 10;
echo $total_stairs= $number_of_floors*$stairs_per_floor;
?>
Lead to an error when included inside of a class:
<?php
// Class
class Building {
// Object variables/properties
public $number_of_floors = 5; // These buildings have 5 floors
public $stairs_per_floor= 10;
public $total_stairs= $number_of_floors*$stairs_per_floor;
private $color;
// Class constructor
public function __construct($paint) {
$this->color = $paint;
}
public function describe() {
printf('This building has %d floors. It is %s in color.',
$this->number_of_floors,
$this->color
);
}
}
// Build a building and paint it red
$bldgA = new Building('red');
// Tell us how many floors these buildings have, and their painted color
$bldgA->describe();
?>
If you remove
public $total_stairs= $number_of_floors*$stairs_per_floor;
Everything works.
Are you not allowed to write arithmetic expressions inside of a class if they are outside of a function? What type of code that interprets correctly in procedural programming will cause an error when included in a class (outside of a function)?
You can not do the operation at the time of defining them. Instead you should add this to your constructor and do:
$this->total_stairs = $this->number_of_floors * $this->stairs_per_floor;
Furthermore I advise you to use the generally accepted coding standards of PHP which would mean, not to use underscores in variable names.
public $totalStairs;
public $numberOfFloors;
public $stairsPerFloor;
Even more important is the choice of meaningful and readable variables names. So $bldgA should be:
$buildingA
you can't assign value by mathematical calculation while defining variable. Calculate value in constructor.
<?php
// Class
class Building {
// Object variables/properties
public $number_of_floors = 5; // These buildings have 5 floors
public $stairs_per_floor= 10;
public $total_stairs=0;
private $color;
// Class constructor
public function __construct($paint) {
$this->color = $paint;
$this->total_stairs = $number_of_floors*$stairs_per_floor;
}
public function describe() {
printf('This building has %d floors. It is %s in color.',
$this->number_of_floors,
$this->color
);
}
}
// Build a building and paint it red
$bldgA = new Building('red');
// Tell us how many floors these buildings have, and their painted color
$bldgA->describe();
?>
To answer your question: within an object oriented design, all code belongs inside a method; either a "special" method like the constructor, within a regular method, or (in languages other than PHP) in getter/setter methods (http://php.net/manual/en/language.oop5.properties.php has a way of implementing those in PHP).
Outside of methods, you're allowed to declare properties or attributes - but you should think of that really as a declaration, not a way of executing logic. The fact you can assign literals during the declaration is purely a convenience.
Don't assign expressions as variable. Do it in the Constructor:
$this->total_stairs = $this->number_of_floors * $this->stairs_per_floor;
or do
public $total_stairs= $this->number_of_floors * $this->stairs_per_floor;
you have to use the instance variables, without $this-> they are interpreted as local variables.
$this->total_stairs = $this->number_of_floors*$this->stairs_per_floor;
also, move those to the constructor, as they are (look like) instance specific.
You can't execute expressions when define properties, even with constants and heredocs.
Calculate them in __construct method.
I have started building a few applications using OO programing in PHP, however I am not sure If I am doing it the standard way.
Heres an example, if I had a book class
class book{
private $name;
private $id;
private $isbn;
}
There are two scenarios, one, I want to add a brand new book to my database...
should I a) use a function within my new class to create the new book... ie.
$book = new book;
$book->addAsNew($name, $isbn);
Or should I B) have a function completely independent of the class that adds a new book?
Secondly.. when opening my book class, should I have A) a constructor
function __construct( $bookId ){
//Call mysql DB and set $name and $isbn var based on $bookId
}
...
$book = new book( $bookId );
of should I b) have a separate function..
class book{
private $name;
private $id;
private $isbn;
public initiated = 0;
function initiate( $bookId ){
//Load $name and $isbn from DB based on $bookId
$initiated = 1;
}
}
...
$book = new book;
$book = initiate( $bookId );
Is there a standard way most programmers would do this? or is it just mainly at the discretion of the programmer?
You can add parameters to the constructor too, so you could write
book = new Book($name, $isbn).
But in this case, I'd choose to have a class with separate properties, like you have, and create a separate factory class or function to instantiate the book objects.
The same goes for B. Don't put the DB queries in this class. Create a separate BookData object that can act as a factory. It can query the database and return the book object(s). Of course, if you feel a factory class is over complicated, you can create a function too, but hey, you wanted to go OO. ;-)
What you are doing is creating models and data mappers, please refer to:
http://www.devshed.com/c/a/PHP/Implementing-the-Data-Mapper-Design-Pattern-in-PHP-5/
http://www.doctrine-project.org/ - http://www.doctrine-project.org/docs/orm/2.0/en/tutorials/getting-started-xml-edition.html
So your book class is a model, and that model needs to be stored somewhere. Pseudo-code would be:
$book = new Book();
$book
->setName($name)
->setId($id)
->setISBN($isbn);
$bookDataMapper = new BookDataMapper();
$bookDataMapper->save($book);
You could do both!
Calling initiate from the constructor
function __construct( $bookId = null) {
if ($bookId) {
$this->initiate($bookId);
}
}
From a OOP perspective this is nice, because it prevents an empty object.
empty object: An object that issn't a real live object yet, but exists only in code.
But because the $bookId parameter is optional, an empty object is still possible, allowing you to create new book(record)s with the book class.