class Person
{
protected $name;
public function __construct($name)
{
$this->name = $name;
}
}
class Business
{
protected $staff;
public function __construct(Staff $staff)
{
$this->staff = $staff;
}
public function hire(Person $person)
{
$this->staff->add($person);
}
public function getStaffMembers()
{
return $this->staff->members();
}
}
class Staff //staff é uma coleção, logo os membros são um array
{
protected $members = [];
public function __construct($members = [])
{
$this->members = $members;
}
public function add(Person $person)
{
$this->members[] = $person;
}
public function members()
{
return $this->members;
}
}
$daniel = new Person('Daniel Santos'); //name==$daniel santos
$staff = new Staff([$daniel]);
$laracasts = new Business($staff);
$laracasts->hire(new Person("Jorge"));
var_dump($laracasts->getStaffMembers());
I would like to print(implode("",$laracasts->getStaffMembers()); instead of just var_dump() it. Thanks.
Add a __toString "magic method" to your Person class.
class Person
{
protected $name;
public function __construct($name)
{
$this->name = $name;
}
public function __toString()
{
return $this->name;
}
}
__toString provides a string representation of the class, so you can use it in string contexts, like echo $person, or echo implode(', ', $laracasts->getStaffMembers());
In this example I just returned the person's name, but you can do more complex stuff in that method as well (formatting, etc.), as long as it returns a string.
Related
I am pretty sure that we can store reference to an Object's property with an Object of a different class.
But I am stuck with this code.
The __construct() functions of both metro and town assigns the values for $name and $pop of those objects . But I need the __construct() function of the class city to create a new object of either class metro or class town depending on the value of $pop of the object of class city
<?php
class metro
{
public $name;
public $pop;
function __construct($name,$pop)
{
$this->name = $name;
$this->pop = $pop;
}
}
class town
{
public $name;
public $pop;
function __construct($name,$pop)
{
$this->name = $name;
$this->pop = $pop;
}
}
class city
{
public $name;
public $pop;
public $derived_city;
function __construct($name,$pop)
{
$this->name = $name;
$this->pop = $pop;
if ($this->pop >= 50)
{
$derived_city = new metro($this->name,$this->pop);
}
else
{
$derived_city = new town($this->name,$this->pop);
}
}
}
$city1 = new city("Bombay",100);
echo $city1->derived_city->pop;
?>
Do this:
class metro
{
public $name;
public $pop;
function __construct($name,$pop)
{
$this->name = $name;
$this->pop = $pop;
}
}
class town
{
public $name;
public $pop;
function __construct($name,$pop)
{
$this->name = $name;
$this->pop = $pop;
}
}
class city
{
public $name;
public $pop;
public $derived_city;
function __construct($name,$pop)
{
$this->name = $name;
$this->pop = $pop;
if ($this->pop >= 50)
{
$derived_city = new metro($this->name,$this->pop);
}
else
{
$derived_city = new town($this->name,$this->pop);
}
$this->derived_city = $derived_city;
}
}
$city1 = new city("Bombay",100);
print_r($city1->derived_city);
echo $city1->derived_city->pop;
I want have an in-memory data structure to be able to add or remove an item (in this instance a student) into some sort of table (just like a shopping cart) from the collection class I have created. At the moment, it just displays students. For instance, if I click add student, it will pop up below, and I can delete this student from below also.
How I could implement this?
Here is my Member.php class
<?php
class Member {
private $name;
private $age;
private $gender;
private $course;
public function __construct($name,$age, $gender, $course){
$this->name = $name;
$this->age = $age;
$this->gender = $gender;
$this->course = $course;
}
public function setName($name) { //Sets the age value
$this->name = $name;
}
public function setAge($age) { //Sets the age value
$this->age = $age;
}
public function setGender($gender) { //Sets the gender value
$this->gender = $gender;
}
public function setCourse ($course) {
$this->course = $course;
}
public function getName() { //Gets the name value
return $this->name;
}
public function getAge() { //Gets the age value
return $this->age;
}
public function getGender() { //Gets the gender value
return $this->gender;
}
public function getCourse() {
return $this->course;
}
}
?>
Here is my ObjectCollection.php
<?php
class ObjectCollection
{
//This is an array to hold line items
private $items_array ;
private $itemCounter; //Count the number of items
public function __construct() {
//Create an array object to hold line items
$this->items_array = array();
$this->itemCounter=0;
}
public function getItemCount(){
return $this->itemCounter;
}
public function addItem($item) {
$this->itemCounter++;
$this->items_array[] = $item;
}
public function getItem($index) {
return $this->items_array[$index];
}
}
?>
And finally displaying this through testcollection.php
<?php
$ObjColl = new ObjectCollection();
$member1 = new Member("Jessica Davidson", 21, "Female", "Computing");
$ObjColl->addItem($member1);
$member2 = new Member("Lucy Barnes", 22, "Female", "History");
$ObjColl->addItem($member2);
$member3 = new Member("Mark Smith", 24, "Male", "Social Science");
$ObjColl->addItem($member3);
for($i = 0;$i < $ObjColl->getItemCount();$i++){
$item = $ObjColl->getItem($i);
if ($item instanceof Member) {
print "<br> University Member: ";
}
print "Name: " . $item->getName();
print ". Age: " . $item->getAge();
print ". Gender: " . $item->getGender();
print ". Enrolled on: " .$item->getCourse() . " course<br>";
}
?>
At first if your ObjectCollection must collect only objects of Member class, use parameter type declaration. It’s good practice in OOP.
public function addItem(Member $item)
At second if you want work with ObjectCollection like with array, implement ArrayAccess and Iterator interfaces.
Example
<?php
class Member{
private $__name;
public function __construct($name){
$this->__name = $name;
}
public function getName(){
return $this->__name;
}
}
class MemberCollection implements ArrayAccess, Iterator{
private $__Collection = [];
private $__position = 0;
public function __construct(){
}
public function offsetSet($offset, $value) {
if (is_null($offset)) {
$this->__Collection[] = $value;
} else {
$this->__Collection[$offset] = $value;
}
}
public function offsetExists($offset) {
return isset($this->__Collection[$offset]);
}
public function offsetUnset($offset) {
unset($this->__Collection[$offset]);
}
public function offsetGet($offset) {
return isset($this->__Collection[$offset]) ? $this->__Collection[$offset] : null;
}
function rewind() {
$this->__position = 0;
}
function current() {
return $this->__Collection[$this->__position];
}
function key() {
return $this->__position;
}
function next() {
++$this->__position;
}
function valid() {
return isset($this->__Collection[$this->__position]);
}
public function addItem(Member $Member){
$this->offsetSet(null, $Member);
}
}
$MC = new MemberCollection();
$Member1 = new Member('Name 1');
$Member2 = new Member('Name 2');
$MC->addItem($Member1);
$MC->addItem($Member2);
foreach ($MC as $Member){
echo '<br>' . $MC->key() . ':<br>';
var_dump($Member->getName());
}
unset($MC[0]); //Delete member from collection
?>
I have a container with some methods like add, get, and search, and within that class I have a variable that is an array holding instances of Car. How to make that object searchable by its name?
For example:
class Container {
private $cars = [];
public function __construct(array $cars = [])
{
$this->cars = $cars;
}
public function add($key, Car $car)
{
$this->cars[$key] = $car;
}
public function get($key)
{
return $this->cars[$key];
}
public function search($car)
{
// ...
}
};
class Car {
private $name;
public function __construct($name = null)
{
$this->name = $name;
}
public function setName($name)
{
$this->name = $name;
}
public function getName()
{
return $this->name;
}
}
You'd need some sort of iterative search like a foreach() or array_filter().
For example:
public function search($car)
{
$matches = array();
foreach ($this->cars as $car) {
if ($car->getName() === $car) {
$matches[] = $car;
}
}
return $matches;
}
Or
public function search($car)
{
return array_filter($this->cars, function ($v) use ($car) {
return $v->getName() === $car;
});
}
I have a database with authors and books, m:n
authors (a_id, ...)
authors_books (a_id, b_id)
books (b_id, ...)
My problem is, that I can't use the constructors to fetch the author/book-data into an array, because I would get an infinite loop.
class Book
{
public $name;
public $authors;
public function __construct($name)
{
$this->name=$name;
$this->authors=$this->Get_Authors();
}
public function Get_Authors()
{
$authors=array();
/* ... (database) */
$authors[]=new Author($name_from_db);
return $authors;
}
}
class Author
{
public $name;
public $books;
public function __construct($name)
{
$this->name=$name;
$this->books=$this->Get_Books();
}
public function Get_Books()
{
$books=array();
/* ... (database) */
$books[]=new Book($name_from_db);
return $books;
}
}
Example:
new Book('book_1');
-> is going to fetch 'author_1' and uses __constructor of Author class
new Author('author_1');
-> is going to fetch 'book_1 and uses __constructor of Book class
...
What is the "best practice" to resolve a m:n relation in PHP classes?
You can use lazy loading here:
class Book {
public $name;
private $_authors = null;
public function __constructor($name) {
$this->name = $name;
}
public function getAuthors() {
if ($this->_authors === null) {
$this->_authors = array();
/* database */
$this->_authors[] = new Author(/**/);
}
return $this->_authors;
}
// You can add some magic getter if you want to access authors as property
public function __get($key) {
if ($key === 'authors') {
return $this->getAuthors();
}
throw new Exception('Unknown property '.$key);
}
}
class Authors {
public $name;
private $_books = null;
public function __constructor($name) {
$this->name = $name;
}
public function getBooks() {
if ($this->_books === null) {
$this->_books = array();
/* database */
$this->_books[] = new Book(/**/);
}
return $this->_books;
}
// You can add some magic getter if you want to access books as property
public function __get($key) {
if ($key === 'books') {
return $this->getBooks();
}
throw new Exception('Unknown property '.$key);
}
}
This will cause that authors/books will be loaded only if you'll need it and won't loop infinitely, but you can reach another problem here:
$author = new Author("Jon Doe");
$book = $author->books[0];
// assuming that book has one author
// $book->authors[0] will not be same object as $author
Solution for that would be to use some third object for loading books and authors, that will store already loaded objects and inject them in proper places
class Library {
private $_books = array();
private $_authors = array();
public function getBooksForAuthor($authorId) {
/* db query... */
$books = array();
while ($row = $stmt->fetch()) {
if (isset($this->_books[$row['id']]) {
$books[] = $this->_books[$row['id']];
} else {
$book = new Book($row);
$this->_books[$row['id']] = $book;
$books[] = $book;
}
}
return $books;
}
/* and similar authorsForBook() method */
}
class Author {
private $_data;
private $_library;
private $_books = null;
public function __constructor($data, $library) {
$this->_data = $data;
$this->_library = $library;
}
public function getBooks() {
if ($this->_books === null) {
$this->_books = $this->_library->getBooksForAuthor($this->_data['id']);
}
return $this->_books;
}
public function __get($key) {
if ($key === 'books') {
return $this->getBooks();
}
if (isset($this->_data[$key]) {
return $this->_data[$key];
}
throw new Exception('Unknown property '.$key);
}
}
/* and similar for book */
Why do you want to load all related object? Use "lazy loading"- don't load all related objects until you need them. In your case it would mean getting related object through their getter method. If you need to get them through property you can implement getters through magic methods.
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
}
}