how to create list of objects in php - php

I am .net developer just started to work on PHP project with Laravel framework. In .net, we can create List frequently. What is the alternate way of doing same in PHP. After that, I want to pass that list as method parameter & accessing list items. I searched on google but can't find anything suitable. I know this may be very basic question from the view point of PHP developers. But I am still in confusion & can not proceed with my work.
eg in .net code, we create list object as -
public List<ReaderInfo> readerInfo = null;
To pass that list object in method -
InitReaderInfo(readerInfo);
Method definition is written as -
public void InitReaderInfo(List<ReaderInfo> reader)
Now, I want to convert the same in PHP.
Any suggestion?

PHP is not a strong type language. It also doesn't support generics or generic methods. That general means you cannot write this:
public List<ReaderInfo> readerInfo = null;
or this:
public void InitReaderInfo(List<ReaderInfo> reader)
There is no easy way to enforce type to list elements just by defining it. However, PHP supports argument types declaration so you can do this:
<?php
class Thing {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function __toString() {
return $this->name;
}
}
class Fruit extends Thing {}
class ThingList {
private $list;
public function __construct(Thing ...$list) {
$this->list = $list;
}
public function __toString() {
return array_reduce($this->list, function ($carry, $item) {
return $carry . $item . "\n";
}, '');
}
}
function PrintThings(ThingList $list) {
// ... do something to the thing list
echo $list;
}
?>
in order to get better type-safety like this:
<?php
// declare a list of thing
$things = new ThingList(
new Thing("apple"),
new Fruit("orange")
);
PrintThings($things);
?>
If you're talking about Laravel specific solution, I suggest you to look at the jcrowe/type-safe-collection library, which you can do similar thing with a lot less labour.

Related

Encapsulated calls in php

I have a project where I am in need of a specific piece of logic, but I am unsure how to express it in OOP php. I have seen things similar to what I need to do in frameworks like Laravel.
Here is an example of how a framework does it:
return View::make("index")->with("name", $name);
So basically I want a static base class Fruit with a public function type that can be used and set independently as a string, such as the following:
return Fruit::type("apple");
Furthermore, I want a 'modifier' sub-call that lets me add another string to that function Fruit::type where the function is aware if the sub-call is made and it's return value. Kind of like this:
return Fruit::type("apple")->quality("outerColor", $color);
A call such as Fruit::type("apple") means that there's a static function call to the class Fruit. As such, you'll need something like this:
class Fruit
{
public static function type($fruitType)
{
if ($fruitType === 'apple') {
$object = new Apple();
}
return $object;
}
}
What you call a sub-call is actually just method chaining. As such, your type function in Fruit class needs to return an object that we can operate on further. In this example we can have an Apple class to do this:
class Apple
{
private $qualities = [];
public function quality($key, $value)
{
$this->qualities[$key] = $param;
return $this;
}
}

Method Chaining and Class Inheritance

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();

PHP OOP design: an object can have several 'modes'. How do I define them?

I have a Display object that handles HTML output of the script. It has a mode property, which defines many aspects of how the output is generated. There are several modes, and I will probably add more later. Each mode implies it's own parameters. For example, an author mode would imply an authorID. A search mode would imply a Search object as a parameter, which would contain query information. A comment mode would imply a postID and commentID parameters.
So, a mode has a name and some number of parameters, depending on the name.
I decided to create a Display_Mode object, which has two properties: name and parameters. But how do I assign parameters to names? So that if I have a comment mode, it would neccessarily mean that there are postID and commentID parameters?
My current solution is this:
class display_mode{
public $name;
public $params;
public function __construct($name)
{
$this->name = $name;
switch ($this->name){
case 'comment':
$this->params = array('postID', `commentID`);
break;
case 'author':
$this->params = array('authorID');
}
//etc..
}
}
This seems a bit messy. Is there a better way?
UPD: given answers led me to ask another question, concerning the whole design, which also provides context for this one.
You're better off abstracting the common functionality of the Display_Mode class into an abstract base class or interface and then defining each individual mode as a class that inherits from the base class (or implements the interface).
These specialised mode classes would then explicitly define the parameters they require in their constructors and/or methods, and would be responsible for producing the output that each "mode" requires.
It's difficult to give more specific advice than this without knowing exactly what your Display_Mode class is supposed to do, however.
The idea here is that you should avoid do-it-all classes in OOP, preferring small, self-contained classes each with a single purpose. By giving each mode its own class that can independently render its content, you're making it easy to change the way display modes work or add new ones. All you have to do is add a new class.
This is known as loose coupling.
The description is kinda confusing, but I would create an adapter for each possible "parameter" of Display. This adapter could provide single interface, independently of the the resource that you want to display.
$parameter = new UnknownPrameter;
$adapterFactory = new AdapterFactory;
$parameter = $adapterFactory->build( $parameter );
$display->present( $parameter );
Where AdapterFactory::build() create a wrapper for the specific type of parameter, that you supplied. The returned instance is a container for that parameter.
This approach would also prevent the computation from accumulating in the constructor, which would make the code harder to test/expand.
#Will Vousden already gave you the answer. This is a quick example of how to approach your problem.
abstract class DisplayMode {
protected $_params = array();
public function __construct(array $params) {
$this->_params = $params;
}
public function hasParameter($key) {
if (array_key_exists($key, $this->_params)) {
return true;
}
return false;
}
public function setParameters(array $params) {
$this->_params = $params;
return $this;
}
public function getParameters() {
return $this->_params;
}
}
class CommentMode extends DisplayMode {
public function getCommentId() {
if ($this->hasParameter('comment_id')) {
return $this->_params['comment_id'];
}
return null;
}
public function getPostId() {
if ($this->hasParameter('post_id')) {
return $this->_params['post_id'];
}
return null;
}
}
class AuthorMode extends DisplayMode {
public function getAuthorId() {
if ($this->hasParameter('author_id')) {
return $this->_params['author_id'];
}
return null;
}
}
$comment = new CommentMode(array('post_id' => 4, 'comment_id' => 2));
$author = new AuthorMode(array('author_id' => 3));
// example
print $comment->getCommentId() . ' - ' . $comment->getPostId() . ' - ' . $author->getAuthorId();

PHP5: Callbacks between Class Objects

I am trying to understand how far I can go with PHP5's closures/callbacks, but I am currently trapped in a glass case of "why doesn't this work".
In the following example, I understand that the use of $this in a callback (especially when the scope changes) isn't going to work, it's just there to show you how I hope to be able to use callbacks/closures.
class Customer {
public $name = '';
public $callback = NULL;
function __construct($name) {
$this->name = $name;
}
function when_enters($callback) {
$this->callback = $callback;
}
function enter_store() {
if(is_callable($this->callback))
call_user_func($this->callback);
}
}
class Salesman {
public $customer = NULL;
function add_customer(&$customer) {
$this->customer =& $customer;
$this->customer->when_enters(function() {
$this->greet_customer();
});
}
function greet_customer() {
echo "Hello, {$this->customer->name}!";
}
}
$salesman = new Salesman();
$customer = new Customer('John');
$salesman->add_customer(&$customer);
$customer->enter_store();
I have been able to reproduce this basic functionally by implementing Salesman as a static class and setting the callback function as Salesman::greet_customer instead of $this->greet_customer().
Basically, what I want to know is... using object instances, is this kind of functionality possible?
In php, call_user_func can accept a two-element array to call a method on a class. So if you do this:
$this->customer->when_enters(array($this,'greet_customer'));
it will do what you want. Another alternative on PHP 5.3.0 or greater is to use a closure along with a local copy of $this:
$this_copy=$this;
$this->customer->when_enters(function() use ($this_copy) {
$this_copy->greet_customer();
});
I have some good news, and some bad news.
The good news is that the next major release of PHP (5.4?) will permit anonymous functions to be properties of a class, and be callable without jumping through hoops, and will allow you to reference $this by binding the function to a specific context.
The bad news is that nobody seems to know when the PHP trunk will be turned into a release.
Now, given that you can't actually reference $this inside the anonymous function, what you can do here is very limited. One option would be to pass the current object to the function:
function enter_store() {
if(is_callable($this->callback))
call_user_func($this->callback, $this);
}
While this will work, and allow you to poke at the object from the function, you'd be limited to methods and properties labeled public. This may or may not be an issue for you.

Php classes (I think)

Is there a way to create a php class (or function) that "simplifies" this
ucfirst(str_replace('_',' ',html_entity_decode(trim($variable), ENT_QUOTES))));
The $variable could "come" from anywhere e.g a global from another function or just a "standard" variable
If you want to have this in a class (as the question title implies), then you should create Filter classes. This is a common thing to do. However, compared to the simple function nesting, it will be much more code to do it properly. The advantage is, you can easily extend and combine filters to virtually any filtering needs you have.
I have whipped up something for you quickly.
interface IFilter {
/**
* #param Mixed $value The value to be filtered
* #return Mixed The filtered value
*/
public function filter($value);
}
All filters must implement the IFilter interface. This is to make sure that whenever you are using a Filter, it has a filter() method that accepts a single $value argument. We cannot enforce return values, but the doc block indicated we expect it to return the filtered value. Two very simple filters would look like this:
class ucFirstFilter implements IFilter
{
public function filter($value) {
return ucfirst($value);
}
}
class TrimFilter implements IFilter
{
public function filter($value) {
return trim($value);
}
}
This is nothing but an object wrapper around two of PHP's native functions. You use it like this:
$trimFilter = new TrimFilter;
echo trimFilter->filter(' trim me ');
// returns 'trim me'
The other two filters are somewhat more complex, because they can be passed more than one argument:
class SeparatorToSeparatorFilter implements IFilter
{
protected $_separator;
protected $_replacement;
public function __construct($separator = '_', $replacement = ' ')
{
$this->_separator = $separator;
$this->_replacement = $replacement;
}
public function filter($value) {
return str_replace($this->_separator, $this->_replacement, $value);
}
}
class HtmlEntityDecodeFilter implements IFilter
{
protected $_quoteStyle;
protected $_charset;
public function __construct($quoteStyle=ENT_COMPAT, $charset='ISO-8859-1')
{
$this->_quoteStyle = $quoteStyle;
$this->_charset = $charset;
}
public function filter($value) {
return html_entity_decode($value, $this->_quoteStyle, $this->_charset);
}
}
As you can see, the configuration of the additional arguments is done through the constructor. I have used some default values, so you only have to supply them when you need to deviate from those. In the case of the second filter, I have used the native function's default settings. This is how you use them:
$trimFilter = new TrimFilter;
$separatorFilter = new SeparatorToSeparatorFilter('-');
echo $separatorFilter->filter($trimFilter->filter(' trim-me '));
// returns 'trim me';
Now you might be tempted to add multiple filterings into a single Filter class. Dont. Each Filter should do exactly one thing only. There is a better way to combine filters. All you need is a Filter that aggregates multiple other filters aka a FilterChain:
class FilterChain implements IFilter
{
protected $_filters;
public function __construct()
{
$this->_filters = new SplObjectStorage;
}
public function chain(IFilter $filter)
{
$this->_filters->attach($filter);
return $this;
}
public function remove(IFilter $filter)
{
$this->_filters->detach($filter);
return $this;
}
public function filter($value) {
foreach($this->_filters as $filter) {
$value = $filter->filter($value);
}
return $value;
}
}
The FilterChain accepts any object that implements IFilter and if you call it's filter() method, it will iterate over all chained Filters in the order you chain()ed them and return the passed in $value:
$filterChain = new FilterChain;
$filterChain->chain(new ucFirstFilter)
->chain(new SeparatorToSeparatorFilter)
->chain(new HtmlEntityDecodeFilter(ENT_QUOTES, 'UTF-8'))
->chain(new TrimFilter);
echo $filterChain->filter(' i am a "string_to_be_filtered" ');
// outputs 'i am a "string to be filtered"'
Because the FilterChain also implements IFilter itself, you can also add it to other FilterChains. This is a Composite Pattern. The filter above could be written as
$chain1 = new FilterChain;
$chain1->chain(new ucFirstFilter)
->chain(new SeparatorToSeparatorFilter);
$chain2 = new FilterChain;
$chain2->chain($chain1);
$chain2->chain(new HtmlEntityDecodeFilter(ENT_QUOTES, 'UTF-8'))
->chain(new TrimFilter);
As you can see, it is much more code, but it is also very extensible. The main advantage over having a single function that wraps all native functions into one function is you can combine anything any way you want. If you decided you need another function that does not utilize the trim() function, you'd have to write a completely new function and you'll inadvertently end up with a lot of functions and redundant code for any possible combination of filters. With a FilterChain you simply add the Filters and FilterChains together as needed. And since a FilterChain is an object, you can pass it around freely.
Fortunately, Filter libraries like this already exist, for instance Zend_Filter offers a number of premade filters and can used standalone (e.g. without having to migrate your app to ZF).
If you are using it more than once, then I would definitely put it into a function. That way you won't be repeating all the code.
function functionName($input){
return ucfirst(str_replace('_',' ',html_entity_decode(trim($input), ENT_QUOTES)));
}
echo functionName($variable);

Categories