I wanna create class for making fields, but in Laravel Nova this classes called like Text::make()->placeholder() and etc. This means that methods inside that class is static.
This is my field class:
class Field
{
private $field = [];
public function set($key, $value)
{
$this->field[$key] = $value;
}
public function get()
{
return $this->field;
}
}
class Text
{
private static $field;
public static function make($name)
{
self::$field = new Field;
self::$field->set('#saturn_type', 'string');
self::$field->set('#saturn_key', $name);
self::$field->set('#saturn_field', 'text');
return new Text;
}
public function placeholder($value)
{
self::$field->set('placeholder', $value);
return $this;
}
public function required()
{
self::$field->set('required', true);
return $this;
}
public function translate()
{
self::$field->set('translate', true);
return $this;
}
public function wysiwyg()
{
self::$field->set('wysiwyg', true);
return $this;
}
public function get()
{
return (array) self::$field->get();
}
}
and this is how i call it:
$fields = [
Text::make('name')->placeholder('Full Name'),
Text::make('email')->placeholder('Email'),
Text::make('password')->placeholder('Password'),
]
$lastArray = $fields->map(function ($field) {
return $field->get();
}
);
But when i call get() method for each item in this array to get array, each item returns the last item's name and placeholder because it is static. How can i solve this.
I found the solution. Actually my friend Nijat found ))
class Field
{
private $field = [];
public function set($key, $value)
{
$this->field[$key] = $value;
}
public function get()
{
return $this->field;
}
}
class Text
{
private $field;
public function __construct($name)
{
$this->field = new Field;
$this->field->set('#saturn_type', 'string');
$this->field->set('#saturn_key', $name);
$this->field->set('#saturn_field', 'text');
}
public static function make($name)
{
return new Text($name);
}
public function placeholder($value)
{
$this->field->set('placeholder', $value);
return $this;
}
public function required()
{
$this->field->set('required', true);
return $this;
}
public function translate()
{
$this->field->set('translate', true);
return $this;
}
public function wysiwyg()
{
$this->field->set('wysiwyg', true);
return $this;
}
public function get()
{
return (array) $this->field->get();
}
}
You just have to create constructor then call it in static method.
You can make Text inherit from Field and have a much simpler make method:
class Field
{
public static function make(...$arguments)
{
return new static(...$arguments);
}
// ...
}
This will instantiate the parent class (e.g. Text) and return it, allowing you to keep the chaining. In the methods you can then use $this-> as usual (instead of self::). And move the content of Text::make to the constructor:
class Text extends Field
{
public function __construct($name)
{
$this->set('#saturn_type', 'string');
$this->set('#saturn_key', $name);
$this->set('#saturn_field', 'text');
}
// ...
}
I want to be able to use an object like below, to retrieve new orders and new invoices. I feel like it is most readable, but I am having trouble writing the PHP class to work this way.
$amazon = new Amazon();
$amazon->orders('New')->get();
$amazon->invoices('New')->get();
In my PHP class, how would my get() method be able to distinguish whether to return orders or invoices?
<?php
namespace App\Vendors;
class Amazon
{
private $api_key;
public $orders;
public $invoices;
public function __construct()
{
$this->api_key = config('api.key.amazon');
}
public function orders($status = null)
{
$this->orders = 'orders123';
return $this;
}
public function invoices($status = null)
{
$this->invoices = 'invoices123';
return $this;
}
public function get()
{
// what is the best way to return order or invoice property
// when method is chained?
}
}
A couple of ways, if you want it dynamic and don't do any logic in the methods, use something like __call
<?php
class Amazon {
public $type;
public $method;
public function get()
{
// do logic
// ...
return 'Fetching: '.$this->method.' ['.$this->type.']';
}
public function __call($method, $type)
{
$this->method = $method;
$this->type = $type[0];
return $this;
}
}
$amazon = new Amazon();
echo $amazon->orders('New')->get();
echo $amazon->invoices('New')->get();
If you want to do logic in the methods, do something like:
<?php
class Amazon {
public $type;
public $method;
public function get()
{
return 'Fetching: '.$this->method.' ['.$this->type.']';
}
public function orders($type)
{
$this->method = 'orders';
$this->type = $type;
// do logic
// ...
return $this;
}
public function invoices($type)
{
$this->method = 'invoices';
$this->type = $type;
// do logic
// ...
return $this;
}
}
$amazon = new Amazon();
echo $amazon->orders('New')->get();
echo $amazon->invoices('New')->get();
As orders and invoices are set methods, I would suggest to do as follows:
public function get(array $elements)
{
$result = [];
foreach($elements as $element) {
$result[$element] = $this->$element;
}
return $result;
}
So, you can call get method as:
$amazon = new Amazon();
$amazon->orders('New')->invoices('New')->get(['orders', 'invoices']);
** You need to validate the element's availability within the get method.
Is it possible to chain static methods together using a static class? Say I wanted to do something like this:
$value = TestClass::toValue(5)::add(3)::subtract(2)::add(8)::result();
. . . and obviously I would want $value to be assigned the number 14. Is this possible?
Update: It doesn't work (you can't return "self" - it's not an instance!), but this is where my thoughts have taken me:
class TestClass {
public static $currentValue;
public static function toValue($value) {
self::$currentValue = $value;
}
public static function add($value) {
self::$currentValue = self::$currentValue + $value;
return self;
}
public static function subtract($value) {
self::$currentValue = self::$currentValue - $value;
return self;
}
public static function result() {
return self::$value;
}
}
After working that out, I think it would just make more sense to simply work with a class instance rather than trying to chain static function calls (which doesn't look possible, unless the above example could be tweaked somehow).
I like the solution provided by Camilo above, essentially since all you're doing is altering the value of a static member, and since you do want chaining (even though it's only syntatic sugar), then instantiating TestClass is probably the best way to go.
I'd suggest a Singleton pattern if you want to restrict instantiation of the class:
class TestClass
{
public static $currentValue;
private static $_instance = null;
private function __construct () { }
public static function getInstance ()
{
if (self::$_instance === null) {
self::$_instance = new self;
}
return self::$_instance;
}
public function toValue($value) {
self::$currentValue = $value;
return $this;
}
public function add($value) {
self::$currentValue = self::$currentValue + $value;
return $this;
}
public function subtract($value) {
self::$currentValue = self::$currentValue - $value;
return $this;
}
public function result() {
return self::$currentValue;
}
}
// Example Usage:
$result = TestClass::getInstance ()
->toValue(5)
->add(3)
->subtract(2)
->add(8)
->result();
class oop{
public static $val;
public static function add($var){
static::$val+=$var;
return new static;
}
public static function sub($var){
static::$val-=$var;
return new static;
}
public static function out(){
return static::$val;
}
public static function init($var){
static::$val=$var;
return new static;
}
}
echo oop::init(5)->add(2)->out();
Little crazy code on php5.3... just for fun.
namespace chaining;
class chain
{
static public function one()
{return get_called_class();}
static public function two()
{return get_called_class();}
}
${${${${chain::one()} = chain::two()}::one()}::two()}::one();
With php7 you will be able to use desired syntax because of new Uniform Variable Syntax
<?php
abstract class TestClass {
public static $currentValue;
public static function toValue($value) {
self::$currentValue = $value;
return __CLASS__;
}
public static function add($value) {
self::$currentValue = self::$currentValue + $value;
return __CLASS__;
}
public static function subtract($value) {
self::$currentValue = self::$currentValue - $value;
return __CLASS__;
}
public static function result() {
return self::$currentValue;
}
}
$value = TestClass::toValue(5)::add(3)::subtract(2)::add(8)::result();
echo $value;
Demo
If toValue(x) returns an object, you could do like this:
$value = TestClass::toValue(5)->add(3)->substract(2)->add(8);
Providing that toValue returns a new instance of the object, and each next method mutates it, returning an instance of $this.
This is more accurate, easier, and read-friendly (allows code-completion)
class Calculator
{
public static $value = 0;
protected static $onlyInstance;
protected function __construct ()
{
// disable creation of public instances
}
protected static function getself()
{
if (static::$onlyInstance === null)
{
static::$onlyInstance = new Calculator;
}
return static::$onlyInstance;
}
/**
* add to value
* #param numeric $num
* #return \Calculator
*/
public static function add($num)
{
static::$value += $num;
return static::getself();
}
/**
* substruct
* #param string $num
* #return \Calculator
*/
public static function subtract($num)
{
static::$value -= $num;
return static::getself();
}
/**
* multiple by
* #param string $num
* #return \Calculator
*/
public static function multiple($num)
{
static::$value *= $num;
return static::getself();
}
/**
* devide by
* #param string $num
* #return \Calculator
*/
public static function devide($num)
{
static::$value /= $num;
return static::getself();
}
public static function result()
{
return static::$value;
}
}
Example:
echo Calculator::add(5)
->subtract(2)
->multiple(2.1)
->devide(10)
->result();
result: 0.63
People are overcomplicating this like crazy.
Check this out:
class OopClass
{
public $first;
public $second;
public $third;
public static function make($first)
{
return new OopClass($first);
}
public function __construct($first)
{
$this->first = $first;
}
public function second($second)
{
$this->second = $second;
return $this;
}
public function third($third)
{
$this->third = $third;
return $this;
}
}
Usage:
OopClass::make('Hello')->second('To')->third('World');
You could always use the First method as a static and the remaining as instance methods:
$value = Math::toValue(5)->add(3)->subtract(2)->add(8)->result();
Or better yet:
$value = Math::eval(Math::value(5)->add(3)->subtract(2)->add(8));
class Math {
public $operation;
public $operationValue;
public $args;
public $allOperations = array();
public function __construct($aOperation, $aValue, $theArgs)
{
$this->operation = $aOperation;
$this->operationValue = $aValue;
$this->args = $theArgs;
}
public static function eval($math) {
if(strcasecmp(get_class($math), "Math") == 0){
$newValue = $math->operationValue;
foreach ($math->allOperations as $operationKey=>$currentOperation) {
switch($currentOperation->operation){
case "add":
$newvalue = $currentOperation->operationValue + $currentOperation->args;
break;
case "subtract":
$newvalue = $currentOperation->operationValue - $currentOperation->args;
break;
}
}
return $newValue;
}
return null;
}
public function add($number){
$math = new Math("add", null, $number);
$this->allOperations[count($this->allOperations)] &= $math;
return $this;
}
public function subtract($number){
$math = new Math("subtract", null, $number);
$this->allOperations[count($this->allOperations)] &= $math;
return $this;
}
public static function value($number){
return new Math("value", $number, null);
}
}
Just an FYI.. I wrote this off the top of my head (right here on the site). So, it may not run, but that is the idea. I could have also did a recursive method call to eval, but I thought this may be simpler. Please let me know if you would like me to elaborate or provide any other help.
Technically you can call a static method on an instance like $object::method() in PHP 7+, so returning a new instance should work as a replacement for return self. And indeed it works.
final class TestClass {
public static $currentValue;
public static function toValue($value) {
self::$currentValue = $value;
return new static();
}
public static function add($value) {
self::$currentValue = self::$currentValue + $value;
return new static();
}
public static function subtract($value) {
self::$currentValue = self::$currentValue - $value;
return new static();
}
public static function result() {
return self::$currentValue;
}
}
$value = TestClass::toValue(5)::add(3)::subtract(2)::add(8)::result();
var_dump($value);
Outputs int(14).
This about same as returning __CLASS__ as used in other answer. I rather hope no-one ever decides to actually use these forms of API, but you asked for it.
In a nutshell... no. :) The resolution operator (::) would work for the TetsClass::toValue(5) part, but everything after that will just give a syntax error.
Once namespaces are implemented in 5.3, you can have "chained" :: operators, but all that'll do is drill down through the namespace tree; it won't be possible to have methods in the middle of things like this.
The best that can be done
class S
{
public static function __callStatic($name,$args)
{
echo 'called S::'.$name . '( )<p>';
return '_t';
}
}
$_t='S';
${${S::X()}::F()}::C();
No, this won't work. The :: operator needs to evaluate back to a class, so after the TestClass::toValue(5) evaluates, the ::add(3) method would only be able to evaluate on the answer of the last one.
So if toValue(5) returned the integer 5, you would basically be calling int(5)::add(3) which obviously is an error.
The most easiest way i have ever found for method chaining from new Instance or Static method of class is as below. I have used Late Static Binding here and i really loved this solution.
I have created a utility to send multiple User Notification on next page using tostr in Laravel.
<?php
namespace App\Utils;
use Session;
use Illuminate\Support\HtmlString;
class Toaster
{
private static $options = [
"closeButton" => false,
"debug" => false,
"newestOnTop" => false,
"progressBar" => false,
"positionClass" => "toast-top-right",
"preventDuplicates" => false,
"onclick" => null,
"showDuration" => "3000",
"hideDuration" => "1000",
"timeOut" => "5000",
"extendedTimeOut" => "1000",
"showEasing" => "swing",
"hideEasing" => "linear",
"showMethod" => "fadeIn",
"hideMethod" => "fadeOut"
];
private static $toastType = "success";
private static $instance;
private static $title;
private static $message;
private static $toastTypes = ["success", "info", "warning", "error"];
public function __construct($options = [])
{
self::$options = array_merge(self::$options, $options);
}
public static function setOptions(array $options = [])
{
self::$options = array_merge(self::$options, $options);
return self::getInstance();
}
public static function setOption($option, $value)
{
self::$options[$option] = $value;
return self::getInstance();
}
private static function getInstance()
{
if(empty(self::$instance) || self::$instance === null)
{
self::setInstance();
}
return self::$instance;
}
private static function setInstance()
{
self::$instance = new static();
}
public static function __callStatic($method, $args)
{
if(in_array($method, self::$toastTypes))
{
self::$toastType = $method;
return self::getInstance()->initToast($method, $args);
}
throw new \Exception("Ohh my god. That toast doesn't exists.");
}
public function __call($method, $args)
{
return self::__callStatic($method, $args);
}
private function initToast($method, $params=[])
{
if(count($params)==2)
{
self::$title = $params[0];
self::$message = $params[1];
}
elseif(count($params)==1)
{
self::$title = ucfirst($method);
self::$message = $params[0];
}
$toasters = [];
if(Session::has('toasters'))
{
$toasters = Session::get('toasters');
}
$toast = [
"options" => self::$options,
"type" => self::$toastType,
"title" => self::$title,
"message" => self::$message
];
$toasters[] = $toast;
Session::forget('toasters');
Session::put('toasters', $toasters);
return $this;
}
public static function renderToasters()
{
$toasters = Session::get('toasters');
$string = '';
if(!empty($toasters))
{
$string .= '<script type="application/javascript">';
$string .= "$(function() {\n";
foreach ($toasters as $toast)
{
$string .= "\n toastr.options = " . json_encode($toast['options'], JSON_PRETTY_PRINT) . ";";
$string .= "\n toastr['{$toast['type']}']('{$toast['message']}', '{$toast['title']}');";
}
$string .= "\n});";
$string .= '</script>';
}
Session::forget('toasters');
return new HtmlString($string);
}
}
This will work as below.
Toaster::success("Success Message", "Success Title")
->setOption('showDuration', 5000)
->warning("Warning Message", "Warning Title")
->error("Error Message");
Fully functional example of method chaining with static attributes:
<?php
class Response
{
static protected $headers = [];
static protected $http_code = 200;
static protected $http_code_msg = '';
static protected $instance = NULL;
protected function __construct() { }
static function getInstance(){
if(static::$instance == NULL){
static::$instance = new static();
}
return static::$instance;
}
public function addHeaders(array $headers)
{
static::$headers = $headers;
return static::getInstance();
}
public function addHeader(string $header)
{
static::$headers[] = $header;
return static::getInstance();
}
public function code(int $http_code, string $msg = NULL)
{
static::$http_code_msg = $msg;
static::$http_code = $http_code;
return static::getInstance();
}
public function send($data, int $http_code = NULL){
$http_code = $http_code != NULL ? $http_code : static::$http_code;
if ($http_code != NULL)
header(trim("HTTP/1.0 ".$http_code.' '.static::$http_code_msg));
if (is_array($data) || is_object($data))
$data = json_encode($data);
echo $data;
exit();
}
function sendError(string $msg_error, int $http_code = null){
$this->send(['error' => $msg_error], $http_code);
}
}
Example of use:
Response::getInstance()->code(400)->sendError("Lacks id in request");
Here's another way without going through a getInstance method (tested on PHP 7.x):
class TestClass
{
private $result = 0;
public function __call($method, $args)
{
return $this->call($method, $args);
}
public static function __callStatic($method, $args)
{
return (new static())->call($method, $args);
}
private function call($method, $args)
{
if (! method_exists($this , '_' . $method)) {
throw new Exception('Call undefined method ' . $method);
}
return $this->{'_' . $method}(...$args);
}
private function _add($num)
{
$this->result += $num;
return $this;
}
private function _subtract($num)
{
$this->result -= $num;
return $this;
}
public function result()
{
return $this->result;
}
}
The class can be used as following:
$res1 = TestClass::add(5)
->add(3)
->subtract(2)
->add(8)
->result();
echo $res1 . PHP_EOL; // 14
$res2 = TestClass::subtract(1)->add(10)->result();
echo $res2 . PHP_EOL; // 9
Also works as:
ExampleClass::withBanners()->withoutTranslations()->collection($values)
Using new static(self::class);
public static function withoutTranslations(): self
{
self::$withoutTranslations = true;
return new static(self::class);
}
public static function withBanners(): self
{
return new static(self::class);
}
public static function collection(values): self
{
return $values;
}
Use PHP 7! If your web provider cannot --> change provider! Don't lock in past.
final class TestClass {
public static $currentValue;
public static function toValue($value) {
self::$currentValue = $value;
return __CLASS__;
}
public static function add($value) {
self::$currentValue = self::$currentValue + $value;
return __CLASS__;
}
public static function subtract($value) {
self::$currentValue = self::$currentValue - $value;
return __CLASS__;
}
public static function result() {
return self::$currentValue;
}
}
And very simple use:
$value = TestClass::toValue(5)::add(3)::subtract(2)::add(8)::result();
var_dump($value);
Return (or throw error):
int(14)
completed contract.
Rule one: most evolved and maintainable is always better.
I'm getting value form Form class by creating object.It's working fine.But I wanna do it using static method.I tried but did not succeed.
public function display()
{
$newform=new Form();
echo "<pre>";
var_dump($newform->getAll());
var_dump($newform->get('name'));
}
<?php
class Form
{
private $value = array();
function __construct() {
// here you can use some validation or escapes
foreach($_POST as $key=>$value)
$this->value[$key] = $value;
}
public function getAll() {
return $this->value;
}
public function get($value) {
$this->value = $_POST[$value];
return $this->value;
}
}
Maybe You should just try to read PHP documentation about static keyword?
Example:
class Form {
private static $value = array();
public static function factory() {
// here you can use some validation or escapes
foreach($_POST as $key => $value) {
static::$value[$key] = $value;
}
}
public static function getAll() {
return static::$value;
}
public static function get($key) {
return static::$value[$key];
}
}
Use:
public function display() {
Form::factory();
echo "<pre>";
var_dump(Form::getAll());
var_dump(Form::get('name'));
echo "</pre>";
}
you do not declare a function as public/private/protected outside of the class
you you want to call this method statically, you may try it
<?php
function display()
{
$newform=new Form($_POST);
echo "<pre>";
var_dump(Form::getAll());
var_dump(Form::get('name'));
}
class Form
{
private static $value = array();
function __construct(){
// here you can use some validation or escapes
function __constract($array){
foreach($array as $key=>$value)
self::$value[$key] = $value;
}
}
public static function getAll(){
return self::$value;
}
public static function get($value){
self::$value = self::$value[$value];
return self::$value;
}
}
Here is an example for getAll method. For get method the same idea:
public function display()
{
var_dump(Form::getAll());
}
class Form
{
private static $value = array();
public static function initPost()
{
foreach($_POST as $key=>$value)
self::$value[$key] = $value;
}
public static function getAll()
{
return self::$value;
}
}
I have the following class written for PHP 5.4.x. Should this work as I expect?
class SqlBuilder {
private $dbTable;
private $action;
private $data;
private $clause;
public function toString() {
// $sql = generate sql string
// [...]
return $sql;
}
[...]
public function setClause($clause) {
$this->clause = $clause;
}
public function setDbTable($dbTable) {
$this->dbTable = $dbTable;
}
public function setAction($action) {
$this->action = $action;
}
}
$sql = (new \dbal\SqlBuilder())
->setAction($this->action)
->setClause($this->clause)
->setDbTable($this->dbTable)
->toString();
I am expecting to be able to access all of my setter methods. Instead I see the following error:
Fatal error: Call to a member function toString() on a non-object )
This seems to work:
$builder= new \dbal\SqlBuilder();
$builder->setAction($this->action)
$builder->setClause($this->clause)
$builder->setDbTable($this->dbTable)
$sql = $builder->toString();
But I know that this works as well:
class Foo
{
public $a = "I'm a!";
public $b = "I'm b!";
public $c;
public function getB() {
return $this->b;
}
public function setC($c) {
$this->c = $c;
return $this;
}
public function getC() {
return $this->c;
}
}
print (new Foo)
->setC($_GET["c"])
->getC(); // I'm c!
I've used this style of syntax in Javascript before. Is there a way to make it work in PHP?
What you are asking about is called method chaining. In order for it to work the way you want, each method call needs to return a reference to the object that you are calling. So,
->setAction($this->action)
// needs to return $this; so that
->setClause($this->clause)
// knows what to operate upon and in turn needs to return $this; so that
->setDbTable($this->dbTable)
// can do the same
Try :
public function setClause($clause) {
$this->clause = $clause;
return $this;
}
public function setDbTable($dbTable) {
$this->dbTable = $dbTable;
return $this;
}
public function setAction($action) {
$this->action = $action;
return $this;
}