Eval code won't work - php

I am trying to make my own template engine, (Don't ask why!)
And will try making:
{{#Form::input("name")}}
In my rendering system i'll make this eval code:
preg_match_all('/\{\{\#(.*?)\}\}/is',$data,$output);
$out="";
foreach ( $output[1] as $variables):
$find = '{{#' . $variables . '}}';
$data = str_replace($find, eval($variables), $data);
endforeach;
But i am getting this error
Parse error: syntax error, unexpected $end in /home/psafari/public_html/slt/classes/template.class.php(43) : eval()'d code on line 1
It should run "Form::input('something')" as specificed in the template engine. What am i doing wrong?

Despite the already uber-relevant comments against building a new templating engine, I'd suggest breaking the string found. Taking your example of {{#Form::input("name")}}, you'd have {{#CLASS_NAME::FUNCTION_NAME(params)}}. So using regex you could break the found string (as you already do), create an instance of or reference the class detected, then call the method parsed using a dynamic call (and obviously fail/error if either is not found).
As for the parameters, you could avoid qualifiers (quotes in this case) and break on every comma, or use the qualifiers and parse it differently via regex again. Your call. For each parameter parsed and found, they'd be added to the function call. In order to avoid eval, and given the fact PHP does not support a random number of arguments (such as Python does with args and kwargs), having an array as the single parameter for the functions you'll use on the template files.
You could also have sort of an 'interface' function that accepts a certain number of parameters that then receives the function (or class + function names), counts the number of parameters it finds and finally relays the call to the actual underlying function based on the correct number of parameters found. Though the more you add the more obscure the processing becomes - assuming users of your templating engine will be able to define new template methods, it's a very bad idea to use this second route (as you'd have to support up to N parameters on these interface functions).

Related

How to find function calls using exact number of parameter

Given a system written in php 5.6 with a function declared like this:
function doSometing($param1 = '', $param2 = '', $param3 = '', $param4 = '', $param5 = '') {...}
I want to list all the calls using fifth parameter $param5.
Consider that uses may be with variable formats:
Irrelevant spaces, breaklines, tabs, etc.
Arguments passed as pure strings or variable names or any other php trick
Complex example:
doSometing( 'loreIpsum',$Loreipsum, 'loreipsum',
"loreipsum", 'Target') ;
Maybe an IDE feature or plugin? Maybe Regexp expression (I'm newbie with it)?
Depending on the tools you have at hand there are two options that I can suggest:
1.) If you are using PHPStorm, you can do the following:
Go to the definition of your doSomething function and temporarily remove the fifth parameter from the function signature (or comment it out)
Then run the following PHPStorm inspection on your code base: "PHP => Code Smells => Parameter numbers mismatch declaration" (see
PHPStorm will show you all occurences where this problem occurred and with that the function calls where too many parameters (here 5) are passed to the function
2.) You can use a regular expression to search for specific function calls, for instance via your IDE RegEx search. But be aware that it will be rather tricky to design such a regex because your function can be called with variables, method calls on an object, strings, integers, etc.
But if you are sure that you are only passing in variables, numbers and strings it should be doable...

What is a dereferencable scalar in PHP?

Recently, I was following this PHP talk See it on YouTube. There is a part about new features in PHP7 that is a really strange stuff for me (in "Uniform variable syntax" part of the talk), which wrote:
// support all operations on dereferencable scalars
// (not very useful)
"string"->toLower()
What is a dereferencable scalar? I know when I call a method on a non-object, for example:
echo "string"->toLower();
I'll get the following Error in PHP7:
Fatal Error: Uncaught Error: Call to a member function toLower() on string
Also, I cannot find a way to declare methods on strings (like something we see in JavaScript); as I know, there is no way to do it.
So, what is the code above saying? How can we do the stuff above? What is the use case for it? Saying it generally, what is "string"->toLower()?
(Editted) Note: While the PHP talks says it exists as of PHP 7.0, it seems to be a mistake by Mr. Lerdorf (it could be a rejected patch, for example).
Thanks in advance.
Short answer: this would be a syntax sugar.
Longer answer: This is a way to call functions with the syntax which aligns with the object syntax.
For example, an object (i.e. a class instance) could have a method called "length()". The invocation of this method would be expressed with the following "arrow" syntax:
$length = $myObject->length();
But, for example, to get a length of a string, you can't currently use the same syntax, because strings are not objects. Instead, you must put the variable name within the parentheses, as a parameter to the strlen function , i.e.:
$length = strlen($myString);
What you have mentioned is an idea to unify the syntax, i.e.
$length = $myString->strlen();
would be another possible syntax to call the strlen function. This would make operations on scalars (and arrays) syntactically closer to the objects' method calls.
Note that PHP doesn't support this syntax yet, as of 2018-09-14.

Avoid a "PHP Strict standards" warning with parentheses? [duplicate]

It was noted in another question that wrapping the result of a PHP function call in parentheses can somehow convert the result into a fully-fledged expression, such that the following works:
<?php
error_reporting(E_ALL | E_STRICT);
function get_array() {
return array();
}
function foo() {
// return reset(get_array());
// ^ error: "Only variables should be passed by reference"
return reset((get_array()));
// ^ OK
}
foo();
I'm trying to find anything in the documentation to explicitly and unambiguously explain what is happening here. Unlike in C++, I don't know enough about the PHP grammar and its treatment of statements/expressions to derive it myself.
Is there anything hidden in the documentation regarding this behaviour? If not, can somebody else explain it without resorting to supposition?
Update
I first found this EBNF purporting to represent the PHP grammar, and tried to decode my scripts myself, but eventually gave up.
Then, using phc to generate a .dot file of the two foo() variants, I produced AST images for both scripts using the following commands:
$ yum install phc graphviz
$ phc --dump-ast-dot test1.php > test1.dot
$ dot -Tpng test1.dot > test1.png
$ phc --dump-ast-dot test2.php > test2.dot
$ dot -Tpng test2.dot > test2.png
In both cases the result was exactly the same:
This behavior could be classified as bug, so you should definitely not rely on it.
The (simplified) conditions for the message not to be thrown on a function call are as follows (see the definition of the opcode ZEND_SEND_VAR_NO_REF):
the argument is not a function call (or if it is, it returns by reference), and
the argument is either a reference or it has reference count 1 (if it has reference count 1, it's turned into a reference).
Let's analyze these in more detail.
First point is true (not a function call)
Due to the additional parentheses, PHP no longer detects that the argument is a function call.
When parsing a non empty function argument list there are three possibilities for PHP:
An expr_without_variable
A variable
(A & followed by a variable, for the removed call-time pass by reference feature)
When writing just get_array() PHP sees this as a variable.
(get_array()) on the other hand does not qualify as a variable. It is an expr_without_variable.
This ultimately affects the way the code compiles, namely the extended value of the opcode SEND_VAR_NO_REF will no longer include the flag ZEND_ARG_SEND_FUNCTION, which is the way the function call is detected in the opcode implementation.
Second point is true (the reference count is 1)
At several points, the Zend Engine allows non-references with reference count 1 where references are expected. These details should not be exposed to the user, but unfortunately they are here.
In your example you're returning an array that's not referenced from anywhere else. If it were, you would still get the message, i.e. this second point would not be true.
So the following very similar example does not work:
<?php
$a = array();
function get_array() {
return $GLOBALS['a'];
}
return reset((get_array()));
A) To understand what's happening here, one needs to understand PHP's handling of values/variables and references (PDF, 1.2MB). As stated throughout the documentation: "references are not pointers"; and you can only return variables by reference from a function - nothing else.
In my opinion, that means, any function in PHP will return a reference. But some functions (built in PHP) require values/variables as arguments. Now, if you are nesting function-calls, the inner one returns a reference, while the outer one expects a value. This leads to the 'famous' E_STRICT-error "Only variables should be passed by reference".
$fileName = 'example.txt';
$fileExtension = array_pop(explode('.', $fileName));
// will result in Error 2048: Only variables should be passed by reference in…
B) I found a line in the PHP-syntax description linked in the question.
expr_without_variable = "(" expr ")"
In combination with this sentence from the documentation: "In PHP, almost anything you write is an expression. The simplest yet most accurate way to define an expression is 'anything that has a value'.", this leads me to the conclusion that even (5) is an expression in PHP, which evaluates to an integer with the value 5.
(As $a = 5 is not only an assignment but also an expression, which evalutes to 5.)
Conclusion
If you pass a reference to the expression (...), this expression will return a value, which then may be passed as argument to the outer function. If that (my line of thought) is true, the following two lines should work equivalently:
// what I've used over years: (spaces only added for readability)
$fileExtension = array_pop( ( explode('.', $fileName) ) );
// vs
$fileExtension = array_pop( $tmp = explode('.', $fileName) );
See also PHP 5.0.5: Fatal error: Only variables can be passed by reference; 13.09.2005

Why don't PHP attributes allow functions?

I'm pretty new to PHP, but I've been programming in similar languages for years. I was flummoxed by the following:
class Foo {
public $path = array(
realpath(".")
);
}
It produced a syntax error: Parse error: syntax error, unexpected '(', expecting ')' in test.php on line 5 which is the realpath call.
But this works fine:
$path = array(
realpath(".")
);
After banging my head against this for a while, I was told you can't call functions in an attribute default; you have to do it in __construct. My question is: why?! Is this a "feature" or sloppy implementation? What's the rationale?
The compiler code suggests that this is by design, though I don't know what the official reasoning behind that is. I'm also not sure how much effort it would take to reliably implement this functionality, but there are definitely some limitations in the way that things are currently done.
Though my knowledge of the PHP compiler isn't extensive, I'm going try and illustrate what I believe goes on so that you can see where there is an issue. Your code sample makes a good candidate for this process, so we'll be using that:
class Foo {
public $path = array(
realpath(".")
);
}
As you're well aware, this causes a syntax error. This is a result of the PHP grammar, which makes the following relevant definition:
class_variable_declaration:
//...
| T_VARIABLE '=' static_scalar //...
;
So, when defining the values of variables such as $path, the expected value must match the definition of a static scalar. Unsurprisingly, this is somewhat of a misnomer given that the definition of a static scalar also includes array types whose values are also static scalars:
static_scalar: /* compile-time evaluated scalars */
//...
| T_ARRAY '(' static_array_pair_list ')' // ...
//...
;
Let's assume for a second that the grammar was different, and the noted line in the class variable delcaration rule looked something more like the following which would match your code sample (despite breaking otherwise valid assignments):
class_variable_declaration:
//...
| T_VARIABLE '=' T_ARRAY '(' array_pair_list ')' // ...
;
After recompiling PHP, the sample script would no longer fail with that syntax error. Instead, it would fail with the compile time error "Invalid binding type". Since the code is now valid based on the grammar, this indicates that there actually is something specific in the design of the compiler that's causing trouble. To figure out what that is, let's revert to the original grammar for a moment and imagine that the code sample had a valid assignment of $path = array( 2 );.
Using the grammar as a guide, it's possible to walk through the actions invoked in the compiler code when parsing this code sample. I've left some less important parts out, but the process looks something like this:
// ...
// Begins the class declaration
zend_do_begin_class_declaration(znode, "Foo", znode);
// Set some modifiers on the current znode...
// ...
// Create the array
array_init(znode);
// Add the value we specified
zend_do_add_static_array_element(znode, NULL, 2);
// Declare the property as a member of the class
zend_do_declare_property('$path', znode);
// End the class declaration
zend_do_end_class_declaration(znode, "Foo");
// ...
zend_do_early_binding();
// ...
zend_do_end_compilation();
While the compiler does a lot in these various methods, it's important to note a few things.
A call to zend_do_begin_class_declaration() results in a call to get_next_op(). This means that it adds a new opcode to the current opcode array.
array_init() and zend_do_add_static_array_element() do not generate new opcodes. Instead, the array is immediately created and added to the current class' properties table. Method declarations work in a similar way, via a special case in zend_do_begin_function_declaration().
zend_do_early_binding() consumes the last opcode on the current opcode array, checking for one of the following types before setting it to a NOP:
ZEND_DECLARE_FUNCTION
ZEND_DECLARE_CLASS
ZEND_DECLARE_INHERITED_CLASS
ZEND_VERIFY_ABSTRACT_CLASS
ZEND_ADD_INTERFACE
Note that in the last case, if the opcode type is not one of the expected types, an error is thrown – The "Invalid binding type" error. From this, we can tell that allowing the non-static values to be assigned somehow causes the last opcode to be something other than expected. So, what happens when we use a non-static array with the modified grammar?
Instead of calling array_init(), the compiler prepares the arguments and calls zend_do_init_array(). This in turn calls get_next_op() and adds a new INIT_ARRAY opcode, producing something like the following:
DECLARE_CLASS 'Foo'
SEND_VAL '.'
DO_FCALL 'realpath'
INIT_ARRAY
Herein lies the root of the problem. By adding these opcodes, zend_do_early_binding() gets an unexpected input and throws an exception. As the process of early binding class and function definitions seems fairly integral to the PHP compilation process, it can't just be ignored (though the DECLARE_CLASS production/consumption is kind of messy). Likewise, it's not practical to try and evaluate these additional opcodes inline (you can't be sure that a given function or class has been resolved yet), so there's no way to avoid generating the opcodes.
A potential solution would be to build a new opcode array that was scoped to the class variable declaration, similar to how method definitions are handled. The problem with doing that is deciding when to evaluate such a run-once sequence. Would it be done when the file containing the class is loaded, when the property is first accessed, or when an object of that type is constructed?
As you've pointed out, other dynamic languages have found a way to handle this scenario, so it's not impossible to make that decision and get it to work. From what I can tell though, doing so in the case of PHP wouldn't be a one-line fix, and the language designers seem to have decided that it wasn't something worth including at this point.
My question is: why?! Is this a "feature" or sloppy implementation?
I'd say it's definitely a feature. A class definition is a code blueprint, and not supposed to execute code at the time of is definition. It would break the object's abstraction and encapsulation.
However, this is only my view. I can't say for sure what idea the developers had when defining this.
You can probably achieve something similar like this:
class Foo
{
public $path = __DIR__;
}
IIRC __DIR__ needs php 5.3+, __FILE__ has been around longer
It's a sloppy parser implementation. I don't have the correct terminology to describe it (I think the term "beta reduction" fits in somehow...), but the PHP language parser is more complex and more complicated than it needs to be, and so all sorts of special-casing is required for different language constructs.
My guess would be that you won't be able to have a correct stack trace if the error does not occur on an executable line... Since there can't be any error with initializing values with constants, there's no problem with that, but function can throw exceptions/errors and need to be called within an executable line, and not a declarative one.

Objective-C Default Argument Value

Hey there, quick question here. I'm sure there's a simple answer.
Coming from PHP, I'm used to declaring a function with a default argument value like this:
function myFunction ($array, $sort = FALSE) {
}
I the sort parameter wasn't filled, the function would continue with the default value of false. In Obj-C, is there a similar thing?
I'm working through the exercises in my "Programming In Objective-C 2.0" book, and it wants me to re-write a fraction class print function to default-ly not reduce the fraction, but if the value TRUE for reduce is given, go ahead and reduce the fraction, then print. The chapter (Nor nowhere in the book) gives any information on this.
Thanks for your help guys :D
Default arguments don't exist in Objective-C, per se. They can't really, because the argument count is inextricably tied to the method name — each colon corresponds to one argument.
Objective-C programmers accomplish a similar goal, though, by creating "convenience" methods that just call to a more "primitive" method with some of the arguments filled in with default values. For example, -[NSArray indexOfObject:] could be implemented as version of -[NSArray indexOfObject:inRange:] with an argument of NSMakeRange(0, [self count]) for the inRange: part.
In this case, though, I don't think your book is talking about that. I think it simply means to reduce the fraction if YES is given for the reduce: argument and not reduce it if NO is given.
There are two standard patterns for achieving what you want.
(1) write a many argument form of a method and then provide fewer argument convenience versions. For example, consider the following methods on NSString:
- (NSComparisonResult)compare:(NSString *)string;
- (NSComparisonResult)compare:(NSString *)string options:(NSStringCompareOptions)mask;
- (NSComparisonResult)compare:(NSString *)string options:(NSStringCompareOptions)mask
range:(NSRange)compareRange;
- (NSComparisonResult)compare:(NSString *)string options:(NSStringCompareOptions)mask
range:(NSRange)compareRange locale:(id)locale;
The first three are conceptually [and likely concretely, I didn't check] implemented as calls through to the fourth version. That, is -compare: calls -compare:options:range:locale: with appropriate default values for the three additional arguments.
(2) The other pattern is to implement the many argument version of the method and provide default values when an argument is NULL/nil or set to some value that indicates the default is desired. NSData has methods that are implemented with this pattern. For example:
+ (id)dataWithContentsOfFile:(NSString *)path options:(NSDataReadingOptions)readOptionsMask
error:(NSError **)errorPtr;
If you pass 0 for the readOptionsMask argument, the NSData will read the contents of the file using an internally defined default configuration. That default configuration may change over time.
This question is super old, but in case anyone finds it, the Objective-C version of the PHP code (assuming this is inside a class) would probably be something like this:
-(id)myFunction:(NSArray*)array {
return [self myFunction:array withSort:FALSE];
}
-(id)myFunction:(NSArray*)array withSort:(BOOL)useSort {
// CODE
}
I used (id)s as there is no data type information in your PHP code. Replacing the (id)s with actual data types would be wise.
Terrible necro but for anyone googling this, Xcode 4.5 supports (via Clang) overloading of C functions with __attribute__((overloadable)).
Overloaded functions are allowed to have different numbers of arguments, so if C functions are appropriate for what you're trying to do you can use that to get default argument values.
Here's a contrived example of an .h file with two functions, both called PrintNum:
// Prints a number in the decimal base
__attribute__((overloadable)) extern void PrintNum(NSNumber *number);
// Prints a number in the specified base
__attribute__((overloadable)) extern void PrintNum(NSNumber *number, NSUInteger base);
and in the .m file:
__attribute__((overloadable))
void PrintNum(NSNumber *number) {
PrintNum(number, 10);
}
__attribute__((overloadable))
void PrintNum(NSNumber *number, NSUInteger base) {
// ...
}
Note that the attribute must be specified in all definitions and declarations of the function.
No, default arguments are a feature of C++, not C or Objective-C.
What you would have to do in objective-c is the following (using your psuedo code above):
function myFunction ($array, $sort)
function myFunction ($array)
// call myFunction($array, FALSE)
You can easily achieve the same effect using #define.
The function in your header file:
+(NSDate*)getDateFromYear:(NSUInteger)year month:(NSUInteger)month day:(NSUInteger)day;
Add a #define for parameter function in header file:
#define GetDateFromYearOnly(year) [YourClassName getDateFromYear:year month:1 day:1]
Then your can use the function like:
NSDate* 2015Date = GetDateFromYearOnly(2015);
And you will get an NSDate object with date 2015/01/01.
If the function is not static, build a new function like this:
-(NSDate*)GetDateFromYearOnly:(NSUInteger)year;
And call:
[self getDateFromYear:year month:1 day:1]

Categories