This is not a question about a particular problem, but rather a question asking for advice and / or assistance.
Im a 2nd year student, Im really struggling to get the hang of OOP programming, the fact that my textbook is not very clear, in its explanation is not helping either. I know there are 100's of examples on the web of this probably but I would like to focus specifically on the example used in my textbook.
The introduction to OOP in php starts with this:
EXAMPLE 1
class Person{
var $name;
function set_name($data){
$this->name=$data;
}
function get_name(){
return $this->name;
}
}
$ralph = new Person;
$ralph->set_name('Ralph');
echo 'friend name is '.$ralph->get_name();
Fine I get that no problem However it then goes on giving, what is in my view a very brief explanation on constructors, saying:
Wouldn't it be nice if you could both create and initialize an object at the same time, PHP allows you to do that with constructors.
And then proceeds to give the following example
EXAMPLE 2(UNCLEAR...?)
class Person{
var $name;
function __construct($data)
{
$this->name=$data
}
function set_name($data){
$this->name=$data;
}
function get_name(){
return $this->name;
}
}
$dan = new Person;
echo"Friend name is ", $dan->get_name(), ".";
My Question
I would really like to know what is the difference between the two examples above? Also if a beginner practical example could be included it will be enormously appreciated!
It's no wonder you are confused, that is a very bad example (looks like they forgot to include passing the name to the constructor)! There are also some outdated styles here as well, typically people do not use var anymore for property declarations but declare their scope (public, private, protected, etc.), also some syntax errors (missing semicolon), but that is for another day.
What would have made this a lot more clear is if they actually used the new power of the constructor, which for some reason, they did not. Here is an updated example where the constructor is actually being used:
class Person{
private $name;
function __construct($data)
{
$this->name=$data;
}
function set_name($data){
$this->name=$data;
}
function get_name(){
return $this->name;
}
}
// pass the name to the constructor and you can bypass the set_name call
$dan = new Person("Timothy");
echo "Friend name is ", $dan->get_name(), ".";
This definitely gets much more useful than passing scalars, but hopefully it illustrates what constructors can do a little bit better. Constructors are called automatically whenever you instantiate a new object from a class. Let me know if you have any questions.
The difference between two class is first one you can not initialize data at a time but in second class you can initialize data at a time.
In First Class
class Person{
private $name;
function set_name($data){
$this->name=$data;
}
function get_name(){
return $this->name;
}
}
$ralph = new Person; // you can not initialize value here
$ralph->set_name('Ralph');
echo 'friend name is '.$ralph->get_name(); //friend name is Ralph
In second Class
class Person{
private $name;
function __construct($data)
{
$this->name=$data
}
function set_name($data){
$this->name=$data;
}
function get_name(){
return $this->name;
}
}
$dan = new Person('Sahadat'); //you can initialize value here
echo"Friend name is ", $dan->get_name(), "."; //Friend name is Sahadat
$dan->set_name('John');
echo"Friend name is ", $dan->get_name(), "."; //Friend name is John
The second way is the best way.
Here is a simple answer. First you seem to use javascript var in the above code, so I omit this below. As you can see, the Person is the Object of concern. In the above example, the author is adding only a name to a Person object - but a person could have many other characteristics such as age, date of birth etc... So when a person object is initialized, the Person object will have a place to store its $name in memory. Since the the $name property is private, the above code uses setters and getters to set and get the $name property.
class Person{
private $name;
function setName($name){
$this->name = $name;
}
function getName(){
return $this->name;
}
function setName($name){
$this->name = $name;
}
}
$ralph = new Person;
$ralph->set_name('Ralph');
echo 'friend name is '.$ralph->get_name();
// Friend name is Ralph
The second example combines two steps ( btw you seem to have copied the wrong snippet ) the object will accept one parameter $data .
class Person{
private $name;
function __construct($data)
{
$this->name=$data
}
function setName($name){
$this->name=$name;
}
function getName(){
return $this->name;
}
}
$dan = new Person('Dan');
echo"Friend name is ", $dan->get_name(), ".";
//Friend name is Dan
A true object Oriented example should look like this:
class Person{
private $name;
function __construct($data)
{
$this->name=$data
}
function setName($name){
$this->name=$name;
return $this; // return $this to allow chaining of method calls
}
function getName(){
return $this->name;
}
}
Here is the extra, In real world applications, you find stuff like in this example
public function billTo(array $user){
// Create the Bill To info
$billto = new AnetAPI\CustomerAddressType();
$billto->setFirstName($user['firstname']);
$billto->setLastName($user['lastname']);
$billto->setCompany($user['company_name']);
$billto->setAddress($user['address']);
$billto->setCity($user['city']);
$billto->setState($user['state']);
$billto->setZip($user['zipcode']);
$billto->setCountry($user['country']);
$billto->setEmail($user['email']);
$billto->setPhoneNumber($user['phone']);
return $billto;
}
The above functions creates an instance of the class CustomerAddressType() and stores data from the User array ( passed as a parameter ) in that CustomerAddressType instance. Same as the first example given by the author.
Related
I think I have more or less managed to get a grasp on OOP/Inheritance, and the basics of method chaining I think I understood as well. However I am still confused about how to actually use some of it.
I wanted to do something that I've seen when working with Magento before:
In Magento, I've seen some sort of "selector-function" used in method chaining. It's a little hard to put into words, but it was something along the lines of:
$categoryName = Mage::getModel('catalog/category')->load($categoryId)->getName();
It's the load($categoryId) part that interests me, as in, a function that selects some instance of something and allows me to run a function on that specific instance.
Now, I am writing a module that allows me to configure certain promotions on our website. Seeing as we'll have many different promotions and I want them to be easily configurable and modifiable, I wanted to do something similar.
So, if I wanted to be able to do something like this:
$prm = new Promotion();
$prm->addPromo('xmasPromo');
$prm->addPromo('nyPromo');
$prm->getPromo('xmasPromo')->setName('Promotion for Xmas!');
$prm->getPromo('nyPromo')->setName('Promotion for New Years!');
echo $prm->getPromo('xmasPromo')->getName(); // returns: Promotion for Xmas!
echo $prm->getPromo('nyPromo')->getName(); // returns: Promotion for New Years!
How would the class definition for that have to look like?
This may be much more simple or much more complicated than I anticipate. In either case, thanks a lot!
Edit:
So I did some testing around with the info deceze gave me, but I'm still confused.
Bad naming and putting 2 classes in 1 file aside, here's what I did:
class file:
class Promotion {
private $__arr = array();
public function addPromo($name) {
$this->__arr[$name] = new Promo();
}
public function getPromo($name) {
$this->__arr[$name];
}
}
class Promo {
private $name;
public function setName($name) {
$this->name = $name;
}
public function getName() {
return $name;
}
}
and the run file:
require_once 'class.php';
error_reporting(E_ALL);
$prm = new Promotion();
$prm->addPromo('xmasPromo');
$prm->addPromo('nyPromo');
$prm->getPromo('xmasPromo')->setName('Promotion for Xmas!');
$prm->getPromo('nyPromo')->setName('Promotion for New Years!');
echo 'X: '.$prm->getPromo('xmasPromo')->getName(); // returns: Promotion for Xmas!
echo "\n";
echo 'N: '.$prm->getPromo('nyPromo')->getName(); // returns: Promotion for New Years!
This gives me Fatal error: Call to a member function setName() on a non-object in /var/www/test/index.php on line 11.
But why? Shouldn't getPromo() give me back the object?
Thanks again..
Thanks to the great guys here, it works now. In case anyone were to pass by here with the same or a similar question, here's the final, working code:
Classes:
class Promotion {
private $__arr = array();
public function addPromo($name) {
$this->__arr[$name] = new Promo();
}
public function getPromo($name) {
return $this->__arr[$name];
}
}
class Promo {
private $name;
public function setName($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
Test file:
require_once 'class.php';
error_reporting(E_ALL);
$prm = new Promotion();
$prm->addPromo('xmasPromo');
$prm->addPromo('nyPromo');
$prm->getPromo('xmasPromo')->setName('Promotion for Xmas!');
$prm->getPromo('nyPromo')->setName('Promotion for New Years!');
echo 'X: '.$prm->getPromo('xmasPromo')->getName(); // returns: Promotion for Xmas!
echo "\n";
echo 'N: '.$prm->getPromo('nyPromo')->getName(); // returns: Promotion for New Years!
Method chaining is really simple, all it does is use one particular element of PHP's syntax:
When a function returns an object, you can directly continue with -> after that function.
The longhand version can be:
$bar = $foo->bar();
$baz = $bar->baz();
echo $baz;
$foo->bar() returns an object ($bar) which has a method baz(), and that method returns some value ($baz). This can be written in shorthand like so:
echo $foo->bar()->baz();
$foo->bar() still returns an object which has a method baz(), so you can directly call it without assigning it to an intermediate variable. Maybe this makes it more obvious:
echo ( $foo->bar() )->baz();
You're calling the baz() method on whatever $foo->bar() returns.
$prm->getPromo('xmasPromo')->setName('Promotion for Xmas!');
As such, in your above case, all you need to do is to return an object which has the method setName from getPromo. I would assume getPromo is supposed to return some object of, say, the Promo class. If the Promo class has a method setName, you're all set.
If you want to chain methods you just need to always return the object like this
class Chain {
public function firstChain() {
//do something
return $this;
}
public function secondChain() {
//do some stuff
return $this;
}
}
Than when you have an instance of the class you do like this:
$obj = new Chain();
$obj->fistChain()->secondChain();
I'm new to DI ,using Pimple. Using: php 5.3.5 (wamp), namespaces as well.
I'm refactoring code, using it, but came to a problem (s):
I have my Container that extends from Pimple, lets call it PContainer.php:
class ReuseableContainer extends Pimple{
private function initOutterClass(){
$this['special_location_class'] = '\SpecialLocation';
$this['special_location'] = function($c){return new $c['special_location_class']($c['location_details'],$c['location']);};
}
private function initGlobalFunctions(){
$this['getGeneralDataFromArray'] = function($c){
// returning a function
return function($arr){
foreach ($arr as $key => $value){
// do something
$new_data = $c['general_data_type'];
$new_data->id = $value['id'];
$new_data->name = $value['name'];
}
}
}
public function __construct(){
$this['location_class'] = '\Location';
$this['location_details_class'] = '\LocationDetails';
$this['general_data_type_class'] = '\GeneralDataType';
// define some objects
$this['location'] = function ($c) {
return new $c['location_class']();
};
$this['location_details'] = function ($c) {
return new $c['location_details_class']();
};
$this['general_data_type'] = function ($c) {
return new $c['general_data_type_class']();
};
$this->initOutterClass();
$this->initGlobalFunctions();
}
}
global $container ;
$container = new Pimple();
// embed the SomeContainer container
$container['embed'] = $container->share(function () { return new ReuseableContainer(); });
Ok. So i got a SpecialHelper.php which holds:
final class SpecialLocation{
public $name;
public $location;
public $picture;
public function __construct($location){
$this->location; // dependent on class: Location
}
}
final class SpecialUser{
private $id;
private $location;
public function __construct(\Location $location,$id=''){
$this->id = $id;
$this->location = $location; // $container['embed']['location'];
}
and we got our GeneralHelper.php which holds:
final class Location{
public $lat;
public $lng;
public function __construct($lat='',$lng=''){ $this->lat = $lat; $this->lng = $lng;}
}
final class LocationDetails{
public $id;
public $addresss;
public function __construct($id='',$address=''){$this->id = $id; $this->address = $address;}
}
class GeneralDataType{
public $id;
public $name;
public function getName(){ return $this->name;}
public function getId(){ return $this->id;}
}
and we have our "Special Class" controller, which looks something like this:
final class SpecialController{
public function foor($some_array){
$this->doSomething($some_array);
}
private function doSomething($ret_value){
// do something
$arr = array();
foreach($ret_value as $key => $value){
$something = $container['embed']['getGeneralDataFromArray']($value);
$special_location = $container['embed']['special_location'];
$arr[] = special_location;
}
return $arr;
}
}
Finally we have our main "driver", main.php
require('PContainer.php');
....
...
$some_array = array(....);
$special_controller = new SpecialController();
$special_controller->foor($some_array);
Problems:
1) I had to add initOutterClass function inside ReuseableContainer to decouple the "Special" classes, how could have i decoupled them in a better way? creating a new "special" 9container or something? as EVERYTHING now sitts inside the container.. same goes to the initGlobalFunctions()
2) regarding SpecialHelper.php: i have there SpecialLocation, which one of its properties is a \Location class, i've put it in the constructor , but if i have 20 object properties that are dependent, i must put them all as INPUT params for the constructor?? same goes to the SpecialUser class, it has a $location which if i could i would have made $this->location = $container['embed']['location']; instead of $this->location = $location; resulting in a dependent on the DI! :/
3) I've had to create SpecialHelper.php in a different file, despite wanting to put it in the "special class controller", just so there won't be any unknowns (due to require statement order)
4) MOST importantly: about the "Special class" controller, how do i solve the doSomething method? i must create "Special Location" object inside the loop but i get that $container is unrecognized (despite being global, as of scope probably) but more over it's really dependent! and it's a private function, i don't wish to pass the container to EVERY class i'll use from now on, it isn't IoC right?
Any help is appriciated... i'm trying to understand the best practices..
Thank you
4)Most important: IoC is correct. That an implementation is not correctly working does not reflect the principle of IoC itself.
If you want to use the global $container within a function, then should you use the global keyword within that function. That is how PHP works. Making it static is solving the problem of reference, but does not make a real difference.
An IoC container resolves the dependencies for the caller. The caller does not have to know anything about the internals of the callee - and he doesn't care either. So, there should be some kind of contract by which the exchange of data is regulated. If you have that situation, then you have IoC.
3)That problem is too vague to answer, but imo also not relevant from a practical perspective. Does it work? Ok, good to know. :-)
2)The clue of IoC is the use of contracts. The IoC container is there to connect the caller to the proper contract. The contract resolves to a concrete callee. The callee will return information inline with the contract. The caller understands the answer. Therefor will you need that the input and output in this process is independent of a certain implementation at a certain time. So don't use 20 object properties as input, but use an array or general object instead.
1) I get the idea that you are mixing functional flow (data flow) with technical flow (relationships between classes). An IoC container serves the purpose of the technical flow, it optimizes the dependency in the relationships between classes. For instance, if you want to connect to a database, then might you reuse an existing connection instead of creating new connections all the time. Or if you want to use a special functionality on several moments in your flow, then might you use IoC for that.
I've recently started to work with OO PHP. As a training practice I'm trying to write some simple classes. I have trouble passing a variable from one to another class. Is it even possible?
class group
{
public $array = array();
public function person($name,$surname)
{
$this->person = new person($name,$surname);
}
public function __destruct()
{
print_r($this->array);
}
}
class person
{
public function __construct($name,$surname)
{
$this->name = $name;
$this->surname = $surname;
}
}
$A = new group();
$A->person("John","Doe");
What I want to archieve here is to pass person as another member of group (by simply putting it in group array) for further modifications and sorting. Been googling around but found nothing.
Please forgive me if it's a dumb one. ;)
I'm not sure I totally understand but I think you want:
Class group {
public $members=array();
public function person($name,$surname) {
$this->members[]=new person($name,$surname);
//Creates a new person object and adds it to the internal array.
}
/*...*/
}
A better alternative (seperation of intent) would be:
Class group {
public $members=array();
public function addPerson(person $p) {
$this->members[]=$p;
//Avoids this function need to know how to construct a person object
// which means you can change the constructor, or add other properties
// to the person object before passing it to this group.
}
/*...*/
}
The fix is changing
public function person($name,$surname)
{
$this->person = new person($name,$surname);
}
to
public function person($name,$surname)
{
$this->array[] = new person($name,$surname);
}
$this->person is not being stored in the array otherwise, and is overwritten with each call.
Your group class could improve it's OO by:
changing $array to be more descriptively named
changing the function name person to something more meaningful, like add_person
You should define your properties ('name', 'surname') and give them a suitability visibility
class group
{
public $array = array();
public name;
public surname;
...
Reference: http://php.net/manual/en/language.oop5.visibility.php
Ok so at work we have discovered that this method to fetch related data / objects is something near awesome.
Right to example, i have this class with some related objects inside:
class Country {
private $language; //$language will be an object of class Language
private $regions; //$regions will be an ARRAY of Region objects
//in the constructor i don't load regions or language
//magic method
public function __get($name) {
$fn_name = 'get_' . $name;
if (method_exists($this, $fn_name)) {
return $this->$fn_name();
} else {
if (property_exists($this, $name))
return $this->$name;
}
return $this->$name;
}
public function get_language () {
if (is_object($this->language)) return $this->language;
$this->language = new Language($params); //example
return $this->language;
}
public function get_regions () {
if (is_array($this->regions)) return $this->regions;
$this->regions = array();
$this->regions[] = new Region('fake');
$this->regions[] = new Region('fake2');
return $this->regions;
}
}
so the idea is:
i want an instance of Country, but i dont need its language and regions now.
In another case i need them, so i claim them as properties, and the magic method retrieves them for me only the first time.
$country = new Country();
echo "language is". $country->language->name;
echo "this country has ". sizeof($country->regions)." regions";
This on-demand method (that avoids nested loop of related objects too) has a name?
Maybe lazy loading properties? On-demand properties?
In another case i need them, [...] retrieves them for me only the first time.
Initialize would be the proper wording. This is called Lazy Initialization.
http://en.wikipedia.org/wiki/Lazy_initialization
so i claim them as properties, and the magic method retrieves them
This is called Overloading of properties.
http://php.net/__get
EDIT:
I don't think there's a term for a combination of the two. You can just combine both and get something like "Lazy initialization of properties through overloading".
I have been noticing __construct a lot with classes. I did a little reading and surfing the web, but I couldn't find an explanation I could understand. I am just beginning with OOP.
I was wondering if someone could give me a general idea of what it is, and then a simple example of how it is used with PHP?
__construct was introduced in PHP5 and it is the right way to define your, well, constructors (in PHP4 you used the name of the class for a constructor).
You are not required to define a constructor in your class, but if you wish to pass any parameters on object construction then you need one.
An example could go like this:
class Database {
protected $userName;
protected $password;
protected $dbName;
public function __construct ( $UserName, $Password, $DbName ) {
$this->userName = $UserName;
$this->password = $Password;
$this->dbName = $DbName;
}
}
// and you would use this as:
$db = new Database ( 'user_name', 'password', 'database_name' );
Everything else is explained in the PHP manual: click here
__construct() is the method name for the constructor. The constructor is called on an object after it has been created, and is a good place to put initialisation code, etc.
class Person {
public function __construct() {
// Code called for each new Person we create
}
}
$person = new Person();
A constructor can accept parameters in the normal manner, which are passed when the object is created, e.g.
class Person {
public $name = '';
public function __construct( $name ) {
$this->name = $name;
}
}
$person = new Person( "Joe" );
echo $person->name;
Unlike some other languages (e.g. Java), PHP doesn't support overloading the constructor (that is, having multiple constructors which accept different parameters). You can achieve this effect using static methods.
Note: I retrieved this from the log of the (at time of this writing) accepted answer.
It's to declare the constructor.
class Cat
{
function __construct()
{
echo 'meow';
}
}
Constructors are invoked whenever a new instance of the class is created, in this case, the constructor will be invoked with this line:
$cat = new Cat();
In older PHP versions, the constructor could also be declared using the class name, for ex:
class Cat
{
function Cat()
{
echo 'meow';
}
}
I think this is important to the understanding of the purpose of the constructor.
Even after reading the responses here it took me a few minutes to realise and here is the reason.
I have gotten into a habit of explicitly coding everything that is initiated or occurs. In other words this would be my cat class and how I would call it.
class_cat.php
class cat {
function speak() {
return "meow";
}
}
somepage.php
include('class_cat.php');
mycat = new cat;
$speak = cat->speak();
echo $speak;
Where in #Logan Serman's given "class cat" examples it is assumed that every time you create a new object of class "cat" you want the cat to "meow" rather than waiting for you to call the function to make it meow.
In this way my mind was thinking explicitly where the constructor method uses implicity and this made it hard to understand at first.
The constructor is a method which is automatically called on class instantiation. Which means the contents of a constructor are processed without separate method calls. The contents of a the class keyword parenthesis are passed to the constructor method.
The __construct method is used to pass in parameters when you first create an object--this is called 'defining a constructor method', and is a common thing to do.
However, constructors are optional--so if you don't want to pass any parameters at object construction time, you don't need it.
So:
// Create a new class, and include a __construct method
class Task {
public $title;
public $description;
public function __construct($title, $description){
$this->title = $title;
$this->description = $description;
}
}
// Create a new object, passing in a $title and $description
$task = new Task('Learn OOP','This is a description');
// Try it and see
var_dump($task->title, $task->description);
For more details on what a constructor is, see the manual.
I Hope this Help:
<?php
// The code below creates the class
class Person {
// Creating some properties (variables tied to an object)
public $isAlive = true;
public $firstname;
public $lastname;
public $age;
// Assigning the values
public function __construct($firstname, $lastname, $age) {
$this->firstname = $firstname;
$this->lastname = $lastname;
$this->age = $age;
}
// Creating a method (function tied to an object)
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);
// Printing out, what the greet method returns
echo $me->greet();
?>
For More Information You need to Go to codecademy.com
class Person{
private $fname;
private $lname;
public function __construct($fname,$lname){
$this->fname = $fname;
$this->lname = $lname;
}
}
$objPerson1 = new Person('john','smith');
__construct is always called when creating new objects or they are invoked when initialization takes place.it is suitable for any initialization that the object may need before it is used. __construct method is the first method executed in class.
class Test
{
function __construct($value1,$value2)
{
echo "Inside Construct";
echo $this->value1;
echo $this->value2;
}
}
//
$testObject = new Test('abc','123');
I believe that function __construct () {...} is a piece of code that can be reused again and again in substitution for TheActualFunctionName () {...}.
If you change the CLASS Name you do not have to change within the code because the generic __construct refers always to the actual class name...whatever it is.
You code less...or?
__construct is a method for initializing of new object before it is used.
http://php.net/manual/en/language.oop5.decon.php#object.construct
Note: Parent constructors are not called implicitly if the child class defines a constructor. In order to run a parent constructor, a call to parent::__construct() within the child constructor is required. If the child does not define a constructor then it may be inherited from the parent class just like a normal class method (if it was not declared as private).
__construct simply initiates a class. Suppose you have the following code;
Class Person {
function __construct() {
echo 'Hello';
}
}
$person = new Person();
//the result 'Hello' will be shown.
We did not create another function to echo the word 'Hello'. It simply shows that the keyword __construct is quite useful in initiating a class or an object.
A constructor allows you to initialize an object's properties upon creation of the object.
If you create a __construct() function, PHP will automatically call this function when you create an object from a class.
https://www.w3schools.com/php/php_oop_constructor.asp
Let me explain __construct() without first using the method ... One thing to know about __construct() is that it is an inbuilt function, well let me call it method in PHP. Just as we have print_r() for procedural, the __construct() is an inbuilt for OOP.
That being said, let's explore why you should use this function called __construct().
/*=======Class without __construct()========*/
class ThaddLawItSolution
{
public $description;
public $url;
public $ourServices;
/*===Let us initialize a value to our property via the method set_name()==== */
public function setName($anything,$anythingYouChoose,$anythingAgainYouChoose)
{
$this->description=$anything;
$this->url=$anythingYouChoose;
$this->ourServices=$anythingAgainYouChoose;
}
/*===Let us now display it on our browser peacefully without stress===*/
public function displayOnBrowser()
{
echo "$this->description is a technological company in Nigeria and our domain name is actually $this->url.Please contact us today for our services:$this->ourServices";
}
}
//Creating an object of the class ThaddLawItSolution
$project=new ThaddLawItSolution;
//=======Assigning Values to those properties via the method created====//
$project->setName("Thaddlaw IT Solution", "https://www.thaddlaw.com", "Please view our website");
//===========Let us now display it on the browser=======
$project->displayOnBrowser();
__construct() makes life for you very easy, imaging the time it took me to assigning values to those properties via that method. From the code above, I created an object which is first and then assign values to the properties which is second before finally showing it on the browser. But using __construct() while creating an object i.e. $project= new ThaddLawItSolution; you would do what you did for assigning values to that method immediately while creating the object, i.e.
$project=new ThaddLawItSolution("Thaddlaw IT Solution", "https://www.thaddlaw.com","Please view our website");
//===Let's now use __constructor=====
Just remove that method called setName and put __construct(); and when creating an object, you assign the values at once. That is the point behind the whole __construct() method. But note that this is an inbuilt method or function