Lets say I have two classes Car and Owner
owner.php =>
class Owner {
public $name;
public function setName($name) {
$this->name = $name;
}
}
and respectively the car.php =>
class Car {
public $owner;
public function setOwner(Owner $owner) {
$this->owner = $owner;
}
}
To set and call methods I normally use this approach =>
$owner = new Owner;
$owner->setName('sam');
$car = new Car;
$car->setOwner($owner);
But what if I want it to do using Closure like below, how do I change the setOwner method accordingly?
$car = new Car;
$car->setOwner(function(Owner $owner) {
$owner->setName('sam');
});
What I want to do is something similar to Laravel where
User::where('car_id', $carId)
or
User::where(function($query) {
//code here
})
Car::setOwner() needs to call its argument with an Owner object.
class Car {
public function setOwner(Callable $ownerSetter) {
$o = new Owner;
$ownerSetter($o);
}
}
But this is a strange way to use a closure. A better example might be:
class Car {
private $owner;
public function setOwner($owner) {
$this->owner = $owner;
}
public function doSomethingToOwner(Callable $something) {
$something($this->owner);
}
}
$car->setOwner($owner);
$car->doSomethingToOwner(function($owner) {
echo $owner->name;
});
Related
I wrote a class
class User {
private $cars = array(); //store class Car 's object
public function getCars()
{
return $this->cars;
}
public function setCars($cars)
{
$this->cars = $cars;
}
}
class Car{
private $model;
public function getModel()
{
return $this->model;
}
public function setModel($model)
{
$this->model = $model;
}
}
$user = new User();
$cars = $user->getCars();
$cars[0]->getModel();
When I try to access getModel() php report "Call to undefined method stdClass::getModel()" .
Is there the best practice to deal with such case?
Edit:I filled the getter and setter. In fact, It's generated by phpstorm.
Edit:I tried again and it works well with the demo code below. The original code is too complicated to show. Maybe I caused by my misunderstanding of copying by value and by reference of array.
Please ignore this question. sorry.
class User {
private $cars = array(); //store class Car 's object
public function getCars()
{
return $this->cars;
}
public function setCars($cars)
{
$this->cars = $cars;
}
}
class Car{
private $model;
public function getModel()
{
return $this->model;
}
public function setModel($model)
{
$this->model = $model;
}
}
$user = new User();
$car = new Car();
$car->setModel("Ford");
$arr = $user->getCars();
array_push($arr,$car);
$user->setCars($arr);
foreach($user->getCars() as $car) {
var_dump($car->getModel());
}
You haven't shown your [Getter Setter ] code. You need to create one with something like:
public function setCars($val){
$this->cars = $val;
}
public function getCars(){
return $this->cars;
}
The same applies for getModel()
I have these related classes:
class cars {
public $cars;
public function addCar($name, $car)
{
$this->cars[$name] = $car;
}
public function getCars()
{
return $this->cars;
}
public function getCar($name)
{
return $this->cars[$name];
}
public function getParams()
{
return $this->params;
}
}
$cars = new cars();
class bmw extends cars {
private static $_instance = null;
protected $params;
function __construct()
{
$this->params['param'] = 'foo';
}
public static function init()
{
if (self::$_instance === null) {
self::$_instance = new self;
}
return self::$_instance;
}
}
$cars->addCar( 'bmw', bmw::init() );
Basically i need to access all child classes from parent class. And use methods defined in parent class on those defined child classes. Parent class should not be modified when adding new child classes.
In the end this should work like this:
foreach( $cars->getCars() as $car )
{
foreach( $car->getParams() as $key => $param )
echo "$key = $param";
}
What is the proper way to do this?
It's really difficult to provide an help since it's not so clear what you're trying to achieve.
It seems to me that you need Registry Class (carDealer), an abstract class with common (for each child) methods and a child (Bmw) of this.
So, something like:
// You seems to need what is called sometimes a Registry.
// Something which deal with keeping and delivering a group of 'related' classes, as a register.
class CarsDealer
{
public $cars;
public function addCar($name, $car)
{
$this->cars[$name] = $car;
}
public function getCars()
{
return $this->cars;
}
public function getCar($name)
{
return $this->cars[$name];
}
}
// then you need a basic contract for each concrete classes
// that will have the same nature and so will extend it
abstract class Car
{
protected $params;
public function getParams()
{
return $this->params;
}
}
// finally the concrete class
class Bmw extends Car
{
public function __construct($params = null)
{
$this->params['param'] = $params;
}
}
$carsDealer = new CarsDealer();
$carsDealer->addCar('bmw', new Bmw('foo'));
foreach ($carsDealer->getCars() as $car)
{
foreach ($car->getParams() as $key => $param) {
echo "$key = $param";
}
}
Please pay attention to some basic rules/good practices/conventions:
class naming, always capitalized
Responsibilities (a class Bmw shouldn't have a method getCars, at least not in this example)
Visibility of method, parameters
http://www.php-fig.org/psr/psr-1/
http://www.php-fig.org/psr/psr-2/
Just one another approach, if you just need get this 'params' :-)
class cars {
public $cars;
public function addCar($name, $car)
{
$this->cars[$name] = $car;
}
public function getCars()
{
return $this->cars;
}
public function getCar($name)
{
return $this->cars[$name];
}
public function getParams($obj)
{
return $obj->params;
}
}
$cars = new cars();
class bmw extends cars {
private static $_instance = null;
protected $params;
function __construct()
{
$this->params['param'] = 'foo';
}
public static function init()
{
if (self::$_instance === null) {
self::$_instance = new self;
}
return self::$_instance;
}
}
$cars->addCar( 'bmw', bmw::init() );
print_r( $cars->getParams($cars->getCar('bmw')));
I think code given below works fine (I am busy on learning OOP PHP and not tested these code yet) if I want to retrieve single record. What if I want to loop the record ? How to do that ? Can I use single class to retrieve single and loop record ? If yes how ?
include('class.database.php');
class News
{
protected $id;
protected $title;
protected $detail;
protected $updatedon;
protected $views;
protected $pic;
protected $cat;
protected $reporter;
function __construct ($id);
$newsdb = new Database;
$Query = "SELECT * FROM news WHERE nws_sn =".$id;
$db->query($Query);
$db->singleRecord();
$this->id = $newsdb->Record['nws_sn'];
$this->title = $newsdb->Record['nws_title'];
$this->detail = $newsdb->Record['nws_detail'];
$this->updatedon = $newsdb->Record['nws_time'];
$this->views = $newsdb->Record['nws_view'];
$this->pic = $newsdb->Record['nws_pic'];
$this->cat = $newsdb->Record['nws_cat_id'];
$this->reporter = $newsdb->Record['nws_rptr_id']
}
function getId () {
return $this->id;
}
function getTitle () {
return $this->title;
}
function getDetail () {
return $this->detail;
}
function getViews () {
return $this->views;
}
function getImage () {
return $this->pic;
}
function getTime () {
return $this->updatedon;
}
}
You want to use a constructor to initialize an internal state of your object. In your case you do too much in your constructor which also breaks "single responsibility principle". It seems that "News" is just an entity or data transfer object, so you have to initialize it from outside.
First, I would keep News just to store information received from database.
Second, I would create a static factory method inside News class so it create an actual News object and populate it with data passed to the method from outside. Alternatively, you could create a factory object to create your entity, but since the construction logic is simple enough, I thought it makes sense to keep it inside a single method.
Consider the code below:
class News
{
protected $id;
protected $title;
protected $detail;
protected $updatedon;
protected $views;
protected $pic;
protected $cat;
protected $reporter;
public static createFromRecord($record)
{
$obj = new self();
$obj->setId($record->Record['nws_sn']);
$obj->setTitle($record->Record['nws_title']);
$obj->setDetail($record->Record['nws_detail']);
$obj->setUpdateon($record->Record['nws_time']);
$obj->setViews($record->Record['nws_view']);
$obj->setPic($record->Record['nws_pic']);
$obj->setCat($record->Record['nws_cat_id']);
$obj->setReporter($record->Record['nws_rptr_id']);
return $obj;
}
function getId () {
return $this->id;
}
function getTitle () {
return $this->title;
}
function getDetail () {
return $this->detail;
}
function getViews () {
return $this->views;
}
function getImage () {
return $this->pic;
}
function getTime () {
return $this->updatedon;
}
// ... add public setters for the properties
}
...
$newsdb = new Database;
$Query = "SELECT * FROM news WHERE nws_sn =".$id;
$db->query($Query);
$record = $db->singleRecord();
$newsObject = News::createFromRecord($record);
I have two class es
class Pet {
public $pet = null;
public function setPet(){}
public function getPet(){}
}
and
class B {
public $cat = 'cat';
public $dog = 'bog';
public function cat()
{
$pet = new Pet();
$pet->pet = $this->cat;
}
public function dog()
{
$pet = new Pet();
$pet->pet= $this->dog;
}
}
Can I get this:
$pet = new Pet();
$pet->setPet()->dog();
$pet->getPet(); //dog
I don't believe you can. You could make class B extends Pet. That will allow you to call the functions from the class Pet. Read up on object inheritance, that might help! http://php.net/manual/en/language.oop5.inheritance.php
You can simply extend Class Pet on Class B to call functions from the Pet class. So Class B inherits the functions of Pet.
Class B extends Pet {
// class B functions here...
}
I laughed while I'm writing down my code here..
<?php
class Pet {
public $name;
public function setName($string) {
$this->name = $string;
}
public function getName() {
return $this->name;
}
}
class Dog extends Pet {
public function bark() {
echo "Arf arf!";
}
}
class Cat extends Pet {
public function meow() {
echo "Meoooww~ purrr~";
}
}
$dog = new Dog();
$dog->setName("Jacob");
$dog->bark(); //Arf arf!
echo "Good job, ".$dog->getName()."!"; //Good job, Jacob!
?>
sir you cant call $pet->setPet()->dog() with ->dog() since setPet() is a function and not an object.. just like they said, the right thing to do with your code is to extend it as a super class and declare a Dog Class as the child class..
My variant
class Pet {
public $pet = null;
public function setPet($pet = null)
{
if (is_null($pet)) {
return new B($this);
} else {
$this->pet = $pet;
return $this;
}
}
public function getPet()
{
return $this->pet;
}
}
class B {
protected $pet = null;
protected $cat = 'cat';
protected $dog = 'bog';
public function __construct(Pet $pet)
{
$this->pet = $pet;
}
public function cat()
{
$this->pet->setPet($this->cat);
return $this->pet;
}
public function dog()
{
$this->pet->setPet($this->dog);
return $this->pet;
}
}
$pet = new Pet();
$pet->setPet()->cat();
var_dump($pet->getPet());
Bellow is a PHP script.
I tried to implement the Observer pattern (without MVC structure)... only basic.
The error which is encountered has been specified in a comment.
First I tried to add User objects to the UsersLibrary repository. There was a error such as User::update() does not exists or something.
Why is that error encountered? What fix should be applied and how?
interface IObserver {
public function update(IObservable $sender);
}
interface IObservable {
public function addObserver(IObserver $obj);
public function notify();
}
class UsersLibrary implements IObservable {
private $container;
private $contor;
//private $z;
public function __construct() {//IObserver $a) {
$this->container = array();
$this->contor = 0;
echo "<div>[constructing UsersLibrary...]</div>";
$this->addObserver(new Logger());
//$this->z = $a;
}
public function add($obj) {
echo "<div>[adding a new user...]</div>";
$this->container[$this->contor] = $obj;
$this->contor++;
$this->notify();
}
public function get($index) {
return $this->container[$index];
}
public function addObserver(IObserver $obj) {
$this->container[] = $obj;
}
public function notify() {
echo "<div>[notification in progress...]</div>";
foreach($this->container as $temp) {
//echo $temp;
#################################################################
$temp->update(); //--------ERROR
//Fatal Error: Call to a member function update() on a non-object.
#################################################################
}
//$this->container[0]->update();
//$this->z->update($this);
}
}
class User {
private $id;
private $name;
public function __construct($id, $name) {
$this->id = $id;
$this->name = $name;
}
public function getId() {
return $this->id;
}
public function getName() {
return $this->name;
}
}
class Logger implements IObserver {
public function __construct() {
echo "<div>[constructing Logger...]</div>";
}
public function update(IObservable $sender) {
echo "<div>A new user has been added.</div>";
}
}
$a = new UsersLibrary(); //new Logger());
//$a->add(new User(1, "DemoUser1"));
//$a->add(new User(2, "DemoUser2"));
$a->add("Demo");
echo $a->get(0);
//echo $a->get(0)->getName();
Your User class is not implementing interface IObserver and therefore is not forced to have the method update().
You have to instantiate a new User() in order to add it to the UsersLibrary:
$library = new UsersLibrary();
$user = new User(1, "Demo");
$library->add($user);
Also, you are mixing Users and Loggers into your UsersLibrary container. Maybe think about separating the containers for them?
You are passing a string instead of an object in your $a->add() call. You should either pass in an object, or alter the code in UserLibrary::add() to wrap it's argument in an appropriate object (or do an object lookup of it sees a string, for instance find a user with that name).
$user = new User(1, "Demo");
$a = new UsersLibrary();
$a->add($user);