I am modifying my PHP framework and trying to figure out an easier way to deal with different request types.
Currently I have this block in a controller method
$methodHandler = self::getMethodHandler(__FUNCTION__);
$this->$methodHandler();
Where getMethodHandler is
protected static function getMethodHandler($function) {
return $function."_".ucwords(strtolower(Request::getMethod()));
}
Ideally I want to reduce that two lines into one but PHP ain't having it
$this->self::getMethodHandler(__FUNCTION__)();
Anyway I could do this?
This should work:
$this->{self::getMethodHandler(__FUNCTION__)}();
That will evaluate self::getMethodHandler(__FUNCTION__) and call the result as a method of $this.
Related
I'm playing with PHP and some functional style programming.
I'm using the Functional-PHP library but question is generic to PHP (I'm using 7.2).
I try to create a callable from an imported function but what I get is
TypeError: Failed to create closure from callable: function 'pick' not found or invalid function name
Sample code:
use function Functional\pick;
class A
{
public function execute()
{
$pick1 = \Closure::fromCallable('pick');
}
}
PHP use statements define an alias for the rest of the file, but they won't affect a string referencing an imported function or class.
When you say
use function Functional\pick;
it means that in that file, you can call the Functional\pick function just using pick(...). But if you're using a string to reference it then PHP doesn't know to expand the alias.
The quickest way to resolve this is just to use the fully qualified function name when calling fromCallable:
$pick1 = \Closure::fromCallable('Functional\pick');
echo get_class($pick1);
Closure
Alternatively, if you really wanted to use the alias, you could wrap the call a level deeper with another anonymous function:
use function Functional\pick;
$pick1 = \Closure::fromCallable(function (...$args) { return pick(...$args); });
But that's a lot messier, in my opinion at least.
Edit: There's some decent discussion around this in this recent thread in php-externals
In my screenshot below you can see I have a list of functions that run a routine, fairly in-depth routine.
Previously, I have ben repeating this routine in multiple classes, but now I would like to consolidate those multiple classes into one class and execute only one function, by passing a variable into that function to determine the output to return.
I know how to pass the variable into "one" function, but how can I pass the variable ($this_id) into my multiple functions below? Basically, whatever $this_id is from get_output($this_id); I want that same variable value to be carried over into the other $this_id functions. See screenshot...
I searched online and all answers I've seen show how to do this in a non static way, but I'm only familiar with calling things statically, really. I tried the obj way, but couldn't get it to work.
Example, execution...
$header = 'CustomTheme_output';
$header::get_output('header');
(please disregard any lose code, the code is what I have so far from trying multiple ways. private $id and __construct are from the online solutions I have been trying)
Could you please clue me in on how I can correctly achieve this? I would be sooo happy to get rid of all the repetitive code, folders and files I have! - Thanks!
Either you pass it directly into each method call:
public function foo($this_id) {
$this->bar($this_id);
}
Or you make it a class attribute, and simply ACCESS it from the various methods:
public function foo($this_id) {
$this->id = $this_id;
$this->bar();
}
public function bar() {
do_something($this->id);
}
I am trying to merge two websites created using Laravel 5 into one multisite (yes, I wasn't that experienced when making that decision). The two websites are one for cats and one for dogs.
My problem is that I have a model called Item, the one in cats is storing things in a different table than model Item in dogs.
What I have done in my controller:
protected $posts_class;
public function __construct()
{
$this->items_class = "App\\Models\\" . config('domain') . "\\Item";
}
public function index()
{
$items = $this->items_class::all();
return view('items')->with('items', $items);
}
but it keeps giving an error:
syntax error, unexpected '::' (T_PAAMAYIM_NEKUDOTAYIM)
however if I do:
public function index()
{
$class= $this->items_class;
$items = $class::all();
}
it works.. but I don't want extra variables within the controller method.
I would like to know why the first one doesn't work. If anyone has any recommendations on how to make this multisite work in a better way than this one then I am open to suggestions. Thank you.
The T_PAAMAYIM_NEKUDOTAYIM operator is more commonly known as the Scope Resolution Operator. In the context of PHP, it is used to statically access class methods and variables.
The all() method is a static method on the Eloquent class your model inherits from. As such, it should be called like ClassName::all().
If I understand what you are trying to do correctly, you are trying to use a dynamic variable as the class name. Unfortunately, using $this->someVariable::all() doesn't quite work the way one would expect like that, and as you know, you have to separate it into an individual variable first.
In the spirit of answering your question directly with a way to call it without creating a separate variable, the answer is to use the often forgotten forward_static_call method.
$items = forward_static_call([$this->items_class, 'all']);
If you need to call a static method using this methodology and want to pass an array of parameters, there is also a related function forward_static_call_array().
Reference:
http://php.net/manual/en/language.oop5.paamayim-nekudotayim.php
http://php.net/manual/en/function.forward-static-call.php
http://php.net/manual/en/function.forward-static-call-array.php
i am newer to cakephp. i am trying to write a function which not regarding to view(function). but when i call this function resultCall to undefined function. my code is below
public function records(){
$totalrec = $this->names->find('count');
$pages = ceil($totalrec/$limit);
return $pages;
}
and call it as
$rowsr = records();
please help
Where are you defining and using this function?
If you want to use it absolutely everywhere, define it in the bootstrap-file in config. But be aware that this heavily violates MVC.
Looking at the function, I would guess that you probably want to add this function to the names model. Than you can call it from the Controller this way: $this->Names->records() and in the model this way: $this->records().
actually i was searching for this.
$this->records();
this is working.
Thanks all friends.
There is like a million Template Engine for PHP (Blade, Twig, Smarty, Mustache, ...), and i just hate the idea of creating a new syntax and compiler to write PHP inside HTML! I think it's just not smart (but this isn't what i am here to discuss :) ), what is wrong with writing PHP+HTML the usual way - not for logic - you know, all the variables and loops and defines you wanna use without this {{% %}} or that {:: ::} ! At least for performance sake!
Now, i am using Laravel these days , and it's awesome; it offers (besides Blade and any other 3rd party engine) a plain PHP templates system that uses ob_start/include/ob_get_clean and eval. I was very happy to know that i can avoid learning a new syntax to write PHP inside HTML.
Here is what i am suggesting; what about instead of using ob_* functions with include, we use Closures ? Here is a simple class i put together just to make a point:
class Templates{
static public $templates = array();
static public function create($name, $code){
self::$templates[$name] = $code;
}
static public function run($name, $data){
if(!isset(self::$templates[$name]) || !is_callable(self::$templates[$name])) return false;
return call_user_func(self::$templates[$name], $data);
}
}
And here is how to use it:
Templates::create('test', function($data){
return 'Hi '.$data['name'].' ! ';
});
for($i =0; $i < 10; $i++){
print Templates::run('test', array('name' => 'Jhon'));
}
I think this way is much better, since i wont need to do any output buffering or use eval. And to "separate concerns" here, we can put the Templates::create code in a separate file to keep things clean, in fact this way things can become more simple and elegant; we can make another method to load the template file:
static public function load($name){
self::create($name, include($name.'.php'));
}
And the content of the template file will be as simple as this:
return function($data){
return 'Hi '.$data['name'].' ! ';
};
What do you think of this ? Is there any problems with the approach or the performance of such use of Closures ?
I do not think there are any problems besides that if you put all closure functions into array, that would possibly mean that functions are kinda doing basically the same stuff.
What I mean by this:
In your example you have your functions accepting only 1 parameter. So, not to create a mess all functions you create would accept the same set of parameters and return the same type of data.
However when declared apart, functions may be supposed to do something different and unique.
Why such a solution is suitable: when using some engines, there may be a lot of different functions declared already. To resolve the conflict, they can be "hidden" inside arrays.
Also, some people even say that anonymous functions can be generally better in case of performance. But we have to test that first: to call a function you:
Call a static function run
Check a function for existence
Check a function for callability
And then use call_user_func which returns the return of your function. So, 3x return.
Update
My recomendations for you code:
Make all possible checks only when creating a function. That will greatly buff performance.
static public function create($name, $code){
if (!isset(self::$templates[$name])){
if (is_callable($code)){
self::$templates[$name] = $code ;
} else {
//func is not callable, Throw an exception.
}
} else {
//function already exists. Throw an exception.
}
}
That way you just can have 2x increase in performance:
static public function run($name, $data){
if (isset(self::$templates[$name])){
self::$templates[$name]($data); //Just make a straight call
} else {
//throw new Exception(0, "The func is not defined") ;
}
}