If I create a new PHP class e.g. to simplify form building (yes I know there are some out there) but I am also trying to learn about classes so pls. be patient - thanks ...
OK I create a new class in the usual way
class newform { class details in here }
add a construct function
public function __construct() { function in here }
I can then call that class again in the usual way
$newform = new newform();
so far so good .... (for me anyhow).
Now I can add some args to the function like so
public function __construct($args) { function in here }
and inside the function "go through" the args - which in my case is an array so written like this
$newform = new newform($args = array('arg1'=>'arg1 val','arg2'=>'arg2 val'));
I can do all that but how do I "add further functions" What I mean here is at the moment I have to declare a new class for every input: i.e.
$newform = new newform($args = array('arg1'=>'arg1 val','arg2'=>'arg2 val'));
$newform->textarea;
$newform = new newform($args = array('arg1'=>'arg1 val','arg2'=>'arg2 val'));
$newform->textinput;
That seems "very" long winded to me and therefore wrong.
How do you do something like this (syntax I know is wromg) where textarea and textinput are created in the class a bit like this (but without the args) $this->textarea = '<textarea></textarea>';
$newform = new newform();
$newform->textarea($args);
$newform->textinput($args);
$newform->textarea($args);
What I mean is what additional function/s do you put into the class to allow you to firstly declare the class ($newform = new newform();) then pass $args to items within the class so you can do "something" like above?
Hope I am explaining myself.
If the arguments in the parameter array are related to individual form elements, move the parameter to a new function instead of the passing it to the class constructor. Like so:
class newform {
public function __construct() { }
public function make_textarea(array $args) {
/* do stuff here */
return $formatted_textarea; // a string like '<textarea></textarea>'
}
public function make_input(array $args) {
/* do stuff here */
return $formatted_input; // a string like '<input />'
}
}
Then in your template:
$form = new newForm;
echo $form->make_textarea(array('arg1' => 'val1', 'arg2' => 'val2'));
echo $form->make_input(array('arg1' => 'val3', 'arg2' => 'val4'));
Note: I'm not doing ($args = array('arg1'=> when calling the method. Assigning the array to a variable is not necessary.
Note: Notice the array type hinting: make_textarea(array $args). That's only there to make sure an array is passed to the method. If anything else is passed to the method--a string for example--a Fatal Error will be thrown.
Update - How to use a private method
class Example {
public function do_something(array $args) {
$result = $this->private_method($args);
return $result;
}
private function private_method(array $args) {
/* do stuff here */
return $formatted_args;
}
}
It isn't long-winded to declare functions for each type of tag you want to generate. There are a finite number of tags, and rather than relying on dynamically intercepting function calls via __call you're better off simply defining the methods.
Move most of the internal implementation for each type of tag can be moved to a private method for generating generic HTML tags. Not all form elements share any internal implementation though; tags like <input type="password" /> and <input type="text" /> are obvious candidates for a shared implementation, while <select> elements will require special handling.
The following should give you an idea. When you build your own, don't forget to escape htmlspecialchars where appropriate:
class Form_helper {
// pass boolean false for $contents to build a self-closing "<input />"-style tag
private function html_tag($name, $contents, array $attributes = array() {
$tag = "<$name";
foreach ($attributes as $key => $value) {
$tag .= " $key=\"$value\"";
}
if ($contents === false) {
// self-closing
$tag .= " />";
} else {
$tag .= ">$contents</$name>";
}
return $tag;
}
public function textarea($contents, array $attributes = array()) {
return $this->html_tag('textarea', $contents, $attributes);
}
public function input(array $attributes = array()) {
return $this->html_tag('input', false, $attributes);
}
public function select(array $options) {
// options contains "value"=>"contents" mappings, for production
// option tags in the form <option value="value">contents</option>
$option_tags = '';
foreach ($options as $value => $content) {
$option_tags .= $this->html_tag('option', $content, array('value' => $value));
}
return $this->html_tag('select', $option_tags);
}
}
First of all, you don't have to do this:
$newform = new newform($args = array('arg1'=>'arg1 val','arg2'=>'arg2 val'));
This will suffice:
$newform = new newform(array('arg1'=>'arg1 val','arg2'=>'arg2 val'));
That is, if you want to pass an array as the first argument. Normally, you would do something like this instead:
class newform {
public function __construct($arg1, $arg2) {
// method body here
}
}
$form = new newform('arg1 val', 'arg2 val');
Now, you must keep in mind that a constructor (__construct) is just like another method. So you can do this:
class newform {
public function __construct() {
// method body here
}
public function textarea($name) {
echo '<textarea name="'.$name.'"></textarea>';
}
public funciton textinput($name) {
echo '<input type="text" name="'.$name.'"/>';
}
}
$form = new newform;
$form->textarea('foo');
$form->textinput('bar');
Outputs:
<textarea name="foo"></textarea>
<input type="text" name="bar"/>
I'm not sure what you mean, but my guts tell me that what you need are so-called magic methods:
magic methods / overloading / manual
Best
Raffael
Related
i have a class and i want to call dynamicly all functions starting by default name:
class social_button
{
public function __construct()
{
[...]
}
private function social_facebook()
{[...]}
private function social_instagramm();
{[...]}
private function social_twitter();
{[...]}
[and so on]
}
My matter is, that i wont write all time:
$this->social_facebook();
$this->social_twitter();
...
because it could/will be an endless list.
So here is my questions:
Is there a way to call all functions generic/dynamic starting with "social"?
Like: $this->social_*();
(The " * " is something like a placeholder, which contains an unlimited number of chars)
Sorry for my bad english and much thanks to all answers.
Best regards
You can build the method name with the string concatenation:
$service = 'facebook';
$this->{'social_' . $service}();
or
$service = 'social_facebook';
$this->$service();
If you wan to call all of them, go with:
$services = ['facebook', 'twitter'];
foreach ($services as $service) {
$this->{'social_' . $service}();
}
Edit: See the answer by localheinz below for a better method, using reflection. get_class_methods() will only return public methods.
Building off hsz's answer:
You can get the list of a class' methods using get_class_methods(). Then you can loop through the results, and call the method if it starts with "social_".
// Get the list of methods
$class_methods = get_class_methods("social_button");
// Loop through the list of method names
foreach ($class_methods as $method_name)
{
// Are the first 7 characters "social_"?
if (substr($method_name, 0, 7) == "social_")
{
// Call the method
$this->{$method_name}();
}
}
The problem with the accepted answer is that it will not work with the example posted with the question. get_class_methods() returns only public methods, but the methods in question are marked as private.
If you want to determine all methods, use reflection instead:
class social_button
{
private function social_facebook()
{
return 'Facebook';
}
private function social_instagram()
{
return 'Instagram';
}
private function social_twitter()
{
return 'Twitter';
}
public function all()
{
$reflection = new \ReflectionObject($this);
$prefix = 'social_';
// filter out methods which do not start with the given prefix
$methods = array_filter($reflection->getMethods(), function (\ReflectionMethod $method) use ($prefix) {
return 0 === strpos($method->getName(), $prefix);
});
// invoke all methods and collect the results in an array
$results = array_map(function (\ReflectionMethod $method) {
$name = $method->getName();
return $this->$name();
}, $methods);
return $results;
}
}
$button = new social_button();
var_dump($button->all());
For reference, see:
http://php.net/manual/en/class.reflectionobject.php
http://php.net/manual/en/class.reflectionmethod.php
http://php.net/manual/en/function.array-filter.php
http://php.net/manual/en/function.array-map.php
For an example, see:
https://3v4l.org/qTkOM
In PHP using method chaining how would one go about supplying a functional call after the last method being called in the chain?
Also while using the same instance (see below). This would kill the idea of implementing a destructor.
The end result is a return value and functional call of private "insert()" from the defined chain properties (of course) without having to call it publicly, no matter of the order.
Note, if I echo (__toString) the methods together it would retrieve the final generated unique code which is normal behavior of casting a string.
Example below:
class object
{
private $data;
function __construct($name) {
// ... some other code stuff
}
private function fc($num) {
// some wicked code here
}
public function green($num) {
$this->data .= fc($num*10);
return $this;
}
public function red($num) {
$this->data .= fc($num*25);
return $this;
}
public function blue($num) {
$this->data .= fc($num*1);
return $this;
}
// how to get this baby to fire ?
private function insert() {
// inserting
file_put_content('test_code.txt', $this->data);
}
}
$tss = new object('index_elements');
$tss->blue(100)->green(200)->red(100); // chain 1
$tss->green(0)->red(100)->blue(0); // chain 2
$tss->blue(10)->red(80)->blue(10)->green(0); // chain 3
Chain 1, 2, and 3 would generated an unique code given all the values from the methods and supply an action, e.g. automatically inserting in DB or creating a file (used in this example).
As you can see no string setting or casting or echoing is taking place.
You could keep a list of things that needs to be initialised and whether they
have been so in this instance or not. Then check the list each time you use
one of the initialisation methods. Something like:
class O {
private $init = array
( 'red' => false
, 'green' => false
, 'blue' => false
);
private function isInit() {
$fin = true;
foreach($this->init as $in) {
$fin = $fin && $in;
}
return $fin;
}
public function green($n) {
$this->init['green'] = true;
if($this->isInit()) {
$this->insert();
}
}
public function red($n) {
$this->init['red'] = true;
if($this->isInit()) {
$this->insert();
}
}
public function blue($n) {
$this->init['blue'] = true;
if($this->isInit()) {
$this->insert();
}
}
private function insert() {
echo "whee\n";
}
}
But personally I think this would be more hassle then it's worth. Better imo
to expose your insert method and let the user of you code tell when the
initialisation is finished. So something that should be used like:
$o->red(1)->green(2)->blue(0)->insert();
-update-
If it's the case that it's impossible to predict what functions need to be called
you really do need to be explicit about it. I can't see a way around that. The reason
is that php really can't tell the difference between
$o1 = new A();
$o2 = $o1->stuff();
and
$o2 = (new A())->stuff();
In a language that allows overloading = I guess it would be possible but really
really confusing and generally not a good idea.
It is possible to move the explicit part so that it's not at the end of the call
chain, but I'm not sure if that would make you happier? It would also go against
your desire to not use another instance. It could look something like this:
class O {
public function __construct(InitO $ini) {
// Do stuff
echo "Whee\n";
}
}
class InitO {
public function red($n) {
return $this;
}
public function green($n) {
return $this;
}
public function blue($n) {
return $this;
}
}
$o = new O((new InitO())->red(10)->red(9)->green(7));
You can of course use just one instance by using some other way of wrapping
but the only ways I can think of right now would look a lot uglier.
Im with PeeHaa, this makes no sense! :)
Only chance to have something magically happen after the last chain was used (without being able to look into the future) is a Destructor/Shutdown function OR a manually cast/call to insert()
You can also decide to implement this statically without using objects.
<?php
class Object
{
private static $data;
public static function set($name)
{
// ... some other code stuff
}
private static function fc($num)
{
// some wicked code here
}
public static function green($num)
{
self::$data .= self::fc($num*10);
return new static;
}
public static function red($num)
{
self::$data .= self::fc($num*25);
return new static;
}
public static function blue($num) {
self::$data .= self::fc($num*1);
return new static;
}
// how to get this baby to fire ?
public static function insert()
{
// inserting
file_put_content('test_code.txt', self::$data);
}
}
//$tss = new object('index_elements');
$Object::set('index_elements')->blue(100)->green(200)->red(100)->insert(); // chain 1
$Object::set('index_elements')->green(0)->red(100)->blue(0)->insert(); // chain 2
$Object::set('index_elements')->blue(10)->red(80)->blue(10)->green(0)->insert(); // chain 3
?>
Ok let's see a code example
<?php
// map dummy class
class map
{
// __call magic method
public function __call($name, $args)
{
return $this;
}
}
// now we chain
$map = new map;
// let's find me
$map->start('here')
->go('right')
->then()
->turn('left')
->and('get water')
->dontEat()
->keep('going')
->youShouldSeeMe('smiling');
here we don't know what the last method would be and we need to trigger a kinda operation or event once we hit the end.
According to data structure we can call this the LIFO stack. (Last in first out)
so how did i solve this on PHP?
// i did some back tracing
... back to the __call function
function __call($name, $args)
{
$trace = debug_backtrace()[0];
$line = $trace['line'];
$file = $trace['file'];
$trace = null;
$getFile = file($file);
$file = null;
$getLine = trim($getFile[$line-1]);
$line = null;
$getFile = null;
$split = preg_split("/(->)($name)/", $getLine);
$getLine = null;
if (!preg_match('/[)](->)(\S)/', $split[1]) && preg_match('/[;]$/', $split[1]))
{
// last method called.
var_dump($name); // outputs: youShouldSeeMe
}
$split = null;
return $this;
}
And whoolla we can call anything once we hit the bottom.
*(Notice i use null once i am done with a variable, i come from C family where we manage memory ourselves)
Hope it helps you one way or the other.
I have a similar code snippet like this
class Search
{
public function search($for, $regEx, $flag) //I would like this to be the constructor
{
// logic here
return $this;
}
}
Then I have another class that creates an object from it, later than tries to use the object.
class MyClass
{
public function start()
{
$this->search = new Search();
}
public function load()
{
$this->search($for, $regEx, $flag);
}
}
My question is, is it possible to create an object first THEN give it the parameters?
I know there are some way around this BUT I only ask because I want to use the object like this
$this->search($params);
// I have my methods chained, so I could use it in one line like
// $this->search($params)->hasResults();
if ($this->search->hasResults()) {
echo 'found stuff';
} else {
echo 'didn't find anything';
}
The way I have it set up right now, I would need to use it like this
$this->search->search($params);
if ($this->search->hasResults()) {
echo 'found stuff';
} else {
echo 'didn't find anything';
}
I have a method called search() that does the logic, and I don't want to be redundant in my naming nor do I want to change the name of the method.
I know another way to keep the visual appeal sane I could pass a variable like so
$search = $this->search->search($params);
then
$search->hasResults();
At the same time I am trying to introduce myself to new OOP concepts and learn from them. Would this require passing things by reference? or setting up some type of magic method?
While the previous anwsers show that you can, I wouldn't use it, because it breaks the concept of encapsulation. A proper way to achieve what you want is the following
class Search
{
public function __constructor($for='', $regEx='', $flag='')
{
$this->Setup($for, $regEx, $flag);
}
public function Setup($for, $regEx, $flag)
{
//assign params
//clear last result search
//chain
return $this;
}
public function search()
{
// logic here
return $this;
}
}
In this way, you can reuse the object and have the params in the constructor, without breaking encapsulation.
Yes it is possible
See the below example
<?php
class a{
public $a = 5;
public function __construct($var){
$this->a = $var;
}
}
$delta = new a(10);
echo $delta->a."\n";
$delta->__construct(15);
echo $delta->a."\n";
Output will be:
10 15
Yep, you can.
class Example {
public $any;
function __counstruct($parameters,$some_text) {
$this->any=$some_text;
return $this->any;
}
}
You can call constructor:
$obj = new Example (true,'hello');
echo $obj->any;
$obj->__construct(true,'bye-bye');
echo $obj->any;
I was able to create the visual coding I wanted by using the __call() magic method like this
public function __call($name, $params)
{
$call = ucfirst($name);
$this->$name = new $call($params);
}
from there I could use this
$this->test->search($params);
$this->test->search->hasResults();
I of course now set the search() method to the class constructor
I've made a class and method just for search things on my website. It has too many parameters, the search parameters. My controller grabs data from forms and then pass to the model.
public function search($name, $age, $foo, ... $bar, $lorem) {
Are there any tips of this kind of method? Maybe a good practice about method with too much parameters.
Thanks.
EDIT:
parameters are for the search...
$name should search people with value of $name
$age should search people with value of $age
and so on...
something like the SQL Where clause.
Thanks again.
Darhazer and Zanathel already gave good answers, and I just want to show you one thing: setters with fluent interface. Only when all parameters are optional.
$finder->
setName($name)->
setAge($age)->
setFoo($foo)->
setBar($bar)->
setLorem($lorem)->
search();
or
$query = new SearchQuery($required_argument);
$query->setAge($optional)->setLorem($optional);
$finder->search($query);
to create fluent interface, just write in setter's body return $this;
I like using arrays for functions that might/have many parameters. This sort of approach allows for near infinite expansion of parameters, and is more straightforward and better than using something like func_get_args().
public function search(array $options = array())
{
$defaults = array(
'name' => null,
'age' => null,
'order' => null,
'limit' => null,
'offset' => null,
);
$options = array_merge($defaults, $options);
extract($options);
$select = $this->select();
if (!is_null($name)) {
$select->where('name = ?', $name);
}
if (!is_null($age)) {
$select->where('age = ?', $age, Zend_Db::INT_TYPE);
}
if (!is_null($order)) {
$select->order($order);
}
if (!is_null($limit) || !is_null($offset)) {
$select->limit($limit, $offset);
}
$results = $this->fetchAll($select);
return $results;
}
...or you can use an object oriented approach:
class SearchQuery
{
public function __construct(array $options = null)
{
if (!is_array($options)) {
return;
}
if (array_key_exists('name', $options)) {
$this->setName($options['name']);
}
if (array_key_exists('age', $options)) {
$this->setAge($options['age']);
}
}
public function setName($name)
{
if (!is_string($name)) {
throw InvalidArgumentException('$name must be a string');
}
$this->_name = $name;
return $this;
}
public function setAge($age)
{
if (!is_numeric($age) || $age <= 0) {
throw new InvalidArgumentException('$age must be a positive integer');
}
$this->_age = $age;
return $this;
}
}
// then you can use dependency injection in your main search class
class SearchService
{
public function search(SearchQuery $query)
{
// search
}
}
Introduce Parameter Object
You could pack things into a key=>value based array
Example:
$params = array("Name"=>"Bob", "Age"=32.....);
Class->search($params);
public function search($params) {
// access keys
}
This is a little bit weary because the method could be used incorrectly very easily since any array could be passed in. Some validation may be required in some other method call to verify the arrays contents.
Edit: Since there has been some debate in the comments.... here is another way to do this
Create a new class! A user class that contains name age and such and whatever other demographics. You'll probably use those in other places anyway.
Pass the object or objects in as arguments
$object = new Object();
SearchClass->search($object)
public function search(Object $object){
// Do junk here
}
I'd use the closest simile to value objects, where you pass one object that contains all the necessary parameters as properties to the function.
<?php
class FilterVO {
public $id;
public $name;
// etc ...
}
class SomeCollection {
public function FilterResults(FilterVO $prefs) {
// got all the goodies in here
}
}
?>
make it so that it accepts an array as parameter with many name-value pairs. Then you can use extract($paramsArray) to make all names in array as $variables.
I have a class called contact:
class contacts
{
public $ID;
public $Name;
public $Email;
public $PhoneNumber;
public $CellPhone;
public $IsDealer;
public $DealerID;
}
At some point in my code I would like to point to a property within that class and return the name of the property.
<input type="text"
id="<?php key($objContact->Name)" ?>"
name="<?php key($objContact->Name)" ?>"
value="<?php $_POST['contact'.key($objContact->Name)]" />
My issue being that the key() function only deals with arrays or objects. $objContact->Name itself does not meet these requirements. I know it would be just as simple to type the name itself out into the ID and NAME fields but this is for other code verification uses. Imagine the processor page:
$objContact = new contact();
$objContact->Email = $_POST[$objContact->Email->**GetSinglePropertyName()**];
$objContact->PhoneNumber = $_POST[$objContact->PhoneNumber->**GetSinglePropertyName()**];
This allows me to turn on STRICT and ensure that as I'm writing I'm not creating any fat finger errors along the way that are going to have me denting my head anymore than it presently exist.
UPDATE WITH ANSWER
Answer provided by: linepogl
Now I've taken linepogl's idea and extended is some so it can work very easily with my existing code base. Here's what I've come up with:
class baseData {
public $meta;
public function __construct() {
$this->meta = new Meta($this);
}
}
class Meta {
public function __construct($obj) {
$a = get_object_vars($obj);
foreach ($a as $key => $value){
$this->$key = $key;
}
}
}
class contacts extends baseData
{
public $ID;
public $Name;
public $Email;
public $PhoneNumber;
public $CellPhone;
public $IsDealer;
public $DealerID;
}
Which means I can now call the following code with the desired results:
$objContact = new contacts();
echo($objContact->meta->Email);
So, you want when you type $objContact->Name to take as an answer not the evaluation of this expression but its meta data, which in this case is a ReflectionProperty object.
What you want is a feature that is called metaprogramming ( http://en.wikipedia.org/wiki/Metaprogramming ). Of course php does not support that but there are other languages that do, such as Lisp etc. Rumors say that C# 5.0 will introduce such features.
You can achieve a similar effect by using Reflection ( http://php.net/manual/en/book.reflection.php ). You can get the meta-object of $objContact (ReflectionClass) and iterate over the properties.
So, there is no way to identify a specific property with an identifier. The only way to do is is with a string of its name.
EDIT:
Yet, there a way to simulate it! Write a class like this:
class Meta {
public function __construct($obj) {
$a = get_object_vars($obj);
foreach ($a as $key => $value){
$this->$key = $key; // <-- this can be enhanced to store an
// object with a whole bunch of meta-data,
// but you get the idea.
}
}
}
So now you will be able to do this:
$meta = new Meta($objContact);
echo $meta->Name; // <-- with will return 'Name'!
You can use get_object_vars() like this:
$properties = get_object_vars($objContact);
foreach($properties as $name => $value)
{
if($value == $objContact->Name)
{
//here's youre name
}
}
but with this you will have to assume that $objContact->Name has unique value over all properties...
The key() function works very well with objects. It just doesn't accomplish what you are seemingly trying to do.
$c = new contacts;
end($c);
print key($c); // "DealerID"
You can foreach over object attributes, and PHP remembers the last accessed key(). But I'm not sure if this is what you want.
As alluded to by konforce, is this what you are looking for?
$var = 'Name';
$Obj->$var;//Obj's Name property
...
id="<?php $var ?>" //id="Name"
...
$_POST['contact'.$var];//$_POST['contactName']