Can I create a PHP function that I can call without parentheses?
print is not a variable functions
And :Because this is a language construct
and not a function, it cannot be
called using variable functions
Variable functions
PHP supports the concept of variable
functions. This means that if a
variable name has parentheses appended
to it, PHP will look for a function
with the same name as whatever the
variable evaluates to, and will
attempt to execute it. Among other
things, this can be used to implement
callbacks, function tables, and so
forth.
Creating functions without parentheses in PHP like 'echo'
There simply isn't. "echo" is more of an operator than a function, so you'd actually need to rewrite the PHP interpreter source in order to introduce new "functions" like those.
Edit: Actually, the more accurate term for "echo" is, as eyze has correctly pointed out, language construct rather than operator. http://php.net/manual/de/function.echo.php provides some more information.
php function calls with and without brackets
It is done by implementing the __get
magic method:
class User {
private $posts = [1, 2, 3];
public function __get($key) {
if ($key === 'posts')
return $this->$key;
}
public function posts() {
return count($this->posts);
}
}
$u = new User;
var_dump($u->posts());
var_dump($u->posts);
Outputint(3)
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
Custom PHP function passing arguments without brackets
In the PHP language specifications, the Function calls section mentions:
The syntax of a Function Call Expression is:A function is called via the function-call operator ().
As you can see, a function call expression is made from function name (either the name as a token or a PHP expression that evaluates to it) followed by open parenthesis (function-call-expression:
qualified-name ( argument-expression-list opt )
callable-expression ( argument-expression-list opt )
(
), an optional list of arguments (separated by comma (,
)), followed by the close parenthesis ()
).The parentheses are required and they allow the compiler tell apart a constant from a call of a function without arguments. They also allow it to understand that $var()
is a function call while $var
is not.
Have anyone managed to create a custom PHP function where by passing arguments / parameter wihtout braces, similar to something like echo
?
The short answer is "No, this is not possible in PHP". Above is explained why not.echo
is not a function, it is a language construct. The same for print
, include
/include_once
/require
/require_once
.Using echo
with parenthesis is possible but, in fact, the parenthesis are not part of the echo
, they are part of the expression that is printed by echo
.
The following code is invalid:
echo('one', ' ', 'two');
It would be valid if echo
were a function.Look at this code:
echo('one'), ' ', ('two');
This is apparently invalid PHP error code. And it would be invalid if echo
were a function. But echo
is not a function and the code is valid.Let's assume, for a moment, that echo
is a function and the language allows calling functions with or without parentheses. The line above is ambiguous. What are the arguments of echo
?
Should the compiler think the call to echo
is echo('one')
or ('one')
is just a string in parentheses (a perfectly valid expression) and the arguments of echo
are ('one')
, ' '
and ('two')
?
Instantiate a class with or without parentheses?
Any difference in performance is going to be absolutely negligible.
While both ways are fine, I personally would prefer using new Car();
because usually, a method is being called here, and function/method calls in PHP require ()
. Also, it's more consistent with instantiations that have parameters.
But in the end, it's down to taste. It doesn't matter which way you choose, but when you choose one, stick to it consistently!
laravel - why function call with no parentheses?
Laravel uses the magic function __get
to handle arbitrary attributes.
This calls Illuminate\Database\Eloquent\Model
's getAttribute
function, which checks the model's relations and returns the related item(s) if a relationship is present with that name.
The parentheses are not needed because getAttribute
automatically executes the function items()
when the attribute items
is requested. You can, by the way, request Auth::user()->item();
which will return a query builder you can work with.
Implement method calling without parentheses
Your problem is a parsing problem. However, the bigger problem is that your language is not syntax-directed. This means that the syntax of your language doesn't match its semantics. For example, consider the following program in your language:
f g
This can be parsed in one of two ways, f
applied to g
or g
applied to f
. However, the syntax of the language doesn't make it apparent which one of the two parse trees will be generated. As EJP correctly mentioned, "it is more than a parsing problem, it is a semantic-feedback problem".So, how to you make your language syntax-directed? Let's take a cue from object-oriented languages. For example:
1 plus 2
In an object-oriented language like JavaScript this might be written as:Number.prototype.plus = function (n) { return this + n;};
var sum = (1) .plus (2);
alert(sum);
Invoking a function without parentheses
There are several different ways to call a function without parentheses.
Let's assume you have this function defined:
function greet() {
console.log('hello');
}
Then here follow some ways to call greet
without parentheses:1. As Constructor
With new
you can invoke a function without parentheses:
new greet; // parentheses are optional in this construct.
From MDN on the new
oprator:Syntaxnew constructor[([arguments])]
2. As toString
or valueOf
Implementation
toString
and valueOf
are special methods: they get called implicitly when a conversion is necessary:
var obj = {
toString: function() {
return 'hello';
}
}
'' + obj; // concatenation forces cast to string and call to toString.
You could (ab)use this pattern to call greet
without parentheses:'' + { toString: greet };
Or with valueOf
:+{ valueOf: greet };
valueOf
and toString
are in fact called from the @@toPrimitive method (since ES6), and so you can also implement that method:+{ [Symbol.toPrimitive]: greet }
"" + { [Symbol.toPrimitive]: greet }
2.b Overriding valueOf
in Function Prototype
You could take the previous idea to override the valueOf
method on the Function
prototype:Function.prototype.valueOf = function() {
this.call(this);
// Optional improvement: avoid `NaN` issues when used in expressions.
return 0;
};
Once you have done that, you can write:+greet;
And although there are parentheses involved down the line, the actual triggering invocation has no parentheses. See more about this in the blog "Calling methods in JavaScript, without really calling them"3. As Generator
You could define a generator function (with *
), which returns an iterator. You can call it using the spread syntax or with the for...of
syntax.
First we need a generator variant of the original greet
function:
function* greet_gen() {
console.log('hello');
}
And then we call it without parentheses by defining the @@iterator method:[...{ [Symbol.iterator]: greet_gen }];
Normally generators would have a yield
keyword somewhere, but it is not needed for the function to get called.The last statement invokes the function, but that could also be done with destructuring:
[,] = { [Symbol.iterator]: greet_gen };
or a for ... of
construct, but it has parentheses of its own:for ({} of { [Symbol.iterator]: greet_gen });
Note that you can do the above with the original greet
function as well, but it will trigger an exception in the process, after greet
has been executed (tested on FF and Chrome). You could manage the exception with a try...catch
block.4. As Getter
@jehna1 has a full answer on this, so give him credit. Here is a way to call a function parentheses-less on the global scope, avoiding the deprecated __defineGetter__
method. It uses Object.defineProperty
instead.
We need to create a variant of the original greet
function for this:
Object.defineProperty(window, 'greet_get', { get: greet });
And then:greet_get;
Replace window
with whatever your global object is.You could call the original greet
function without leaving a trace on the global object like this:
Object.defineProperty({}, 'greet', { get: greet }).greet;
But one could argue we do have parentheses here (although they are not involved in the actual invocation).5. As Tag Function
Since ES6 you can call a function passing it a template literal with this syntax:
greet``;
See "Tagged Template Literals".6. As Proxy Handler
Since ES6, you can define a proxy:
var proxy = new Proxy({}, { get: greet } );
And then reading any property value will invoke greet
:proxy._; // even if property not defined, it still triggers greet
There are many variations of this. One more example:var proxy = new Proxy({}, { has: greet } );
1 in proxy; // triggers greet
7. As instance checker
Theinstanceof
operator executes the @@hasInstance
method on the second operand, when defined:1 instanceof { [Symbol.hasInstance]: greet } // triggers greet
Related Topics
PHP Upload File Enhance Security
What Is the Js Equivalent to the PHP Function Number_Format
Make Script Execution to Unlimited
How to Install Gmp for PHP7 on Ubuntu
PHP Class: Global Variable as Property in Class
Mongodb: Benefit of Using Objectid VS a String Containing an Id
Setting Up PHPmailer with Office365 Smtp
Should a Function Use: Return Null;
How to Use Laravel Passport with a Custom Username Column
File_Get_Contents('Php://Input') Always Returns an Empty String
How to Increase by 1 All Keys in an Array
How to Sort Null Values Last Using Eloquent in Laravel
The Behaviour of the or Operator in PHP
Config Nginx for Laravel in a Subfolder
Rename Multiple Order Statuses in Woocommerce
I Want to Find Current Location of User in PHP