I am creating my own language.
The goal is to "compile" it to PHP or Javascript, and, ultimately, to interpret and run it on the same language, to make it look like a "middle-level" language.
Right now, I'm focusing on the aspect of interpreting it in PHP and run it.
At the moment, I'm using regex to split the string and extract the multiple tokens.
This is the regex I have:
/\:((?:cons#(?:\d+(?:\.\d+)?|(?:"(?:(?:\\\\)+"|[^"]|(?:\r\n|\r|\n))*")))|(?:[a-z]+(?:#[a-z]+)?|\^?[\~\&](?:[a-z]+|\d+|\-1)))/g
This is quite hard to read and maintain, even though it works.
Is there a better way of doing this?
Here is an example of the code for my language:
:define:&0:factorial
:param:~0:static
:case
:lower#equal:cons#1
:case:end
:scope
:return:cons#1
:scope:end
:scope
:define:~0:static
:define:~1:static
:require:static
:call:static#sub:^~0:~1 :store:~0
:call:&-1:~0 :store:~1
:call:static#sum:^~0:~1 :store:~0
:return:~0
:scope:end
:define:end
This defines a recursive function to calculate the factorial (not so well written, that isn't important).
The goal is to get what is after the :, including the #. :static#sub is a whole token, saving it without the :.
Everything is the same, except for the token :cons, which can take a value after. The value is a numerical value (integer or float, called static or dynamic in the language, respectively) or a string, which must start and end with ", supporting escaping like \". Multi-line strings aren't supported.
Variables are the ones with ~0, using ^ before will get the value to the above :scope.
Functions are similar, being used &0 instead and &-1 points to the current function (no need for ^&-1 here).
Said this, Is there a better way to get the tokens?
Here you can see it in action: http://regex101.com/r/nF7oF9/2
[Update] To issue the pattern being complicated and maintainability, you can split it using PCRE_EXTENDED, and comments:
preg_match('/
# read constant (?)
\:((?:cons#(?:\d+(?:\.\d+)?|
# read a string (?)
(?:"(?:(?:\\\\)+"|[^"]|(?:\r\n|\r|\n))*")))|
# read an identifier (?)
(?:[a-z]+(?:#[a-z]+)?|
# read whatever
\^?[\~\&](?:[a-z]+|\d+|\-1)))
/gx
', $input)
Beware that all space are ignored, except under certain conditions (\n is normally "safe").
Now, if you want to pimp you lexer and parser, then read that:
What does (f)lex [GNU equivalent of LEX] is simply let you pass a list of regexp, and eventually a "group". You can also try ANTLR and PHP Target Runtime to get the work done.
As for you request, I've made a lexer in the past, following the principle of FLEX. The idea is to cycle through the regexp like FLEX does:
$regexp = [reg1 => STRING, reg2 => ID, reg3 => WS];
$input = ...;
$tokens = [];
while ($input) {
$best = null;
$k = null;
for ($regexp as $re => $kind) {
if (preg_match($re, $input, $match)) {
$best = $match[0];
$k = $kind;
break;
}
}
if (null === $best) {
throw new Exception("could not analyze input, invalid token");
}
$tokens[] = ['kind' => $kind, 'value' => $best];
$input = substr($input, strlen($best)); // move.
}
Since FLEX and Yacc/Bison integrates, the usual pattern is to read until next token (that is, they don't do a loop that read all input before parsing).
The $regexp array can be anything, I expected it to be a "regexp" => "kind" key/value, but you can also an array like that:
$regexp = [['reg' => '...', 'kind' => STRING], ...]
You can also enable/disable regexp using groups (like FLEX groups works): for example, consider the following code:
class Foobar {
const FOOBAR = "arg";
function x() {...}
}
There is no need to activate the string regexp until you need to read an expression (here, the expression is what come after the "="). And there is no need to activate the class identifier when you are actually in a class.
FLEX's group permits to read comments, using a first regexp, activating some group that would ignore other regexp, until some matches is done (like "*/").
Note that this approach is a naïve approach: a lexer like FLEX will actually generate an automaton, which use different state to represent your need (the regexp is itself an automaton).
This use an algorithm of packed indexes or something alike (I used the naïve "for each" because I did not understand the algorithm enough) which is memory and speed efficient.
As I said, it was something I made in the past - something like 6/7 years ago.
It was on Windows.
It was not particularly quick (well it is O(N²) because of the two loops).
I think also that PHP was compiling the regexp each times. Now that I do Java, I use the Pattern implementation which compile the regexp once, and let you reuse it. I don't know PHP does the same by first looking into a regexp cache if there was already a compiled regexp.
I was using preg_match with an offset, to avoid doing the substr($input, ...) at the end.
You should try to use the ANTLR3 PHP Code Generation Target, since the ANTLR grammar editor is pretty easy to use, and you will have a really more readable/maintainable code :)
I am taking over over some webgame code that uses the eval() function in php. I know that this is potentially a serious security issue, so I would like some help vetting the code that checks its argument before I decide whether or not to nix that part of the code. Currently I have removed this section of code from the game until I am sure it's safe, but the loss of functionality is not ideal. I'd rather security-proof this than redesign the entire segment to avoid using eval(), assuming such a thing is possible. The relevant code snip which supposedly prevents malicious code injection is below. $value is a user-input string which we know does not contain ";".
1 $value = eregi_replace("[ \t\r]","",$value);
2 $value = addslashes($value);
3 $value = ereg_replace("[A-z0-9_][\(]","-",$value);
4 $value = ereg_replace("[\$]","-",$value);
5 #eval("\$val = $value;");
Here is my understanding so far:
1) removes all whitespace from $value
2) escapes characters that would need it for a database call (why this is needed is not clear to me)
3) looks for alphanumeric characters followed immediately by \ or ( and replaces the combination of them with -. Presumably this is to remove anything resembling function calls in the string, though why it also removes the character preceding is unclear to me, as is why it would also remove \ after line 2 explicitly adds them.
4) replaces all instances of $ with - in order to avoid anything resembling references to php variables in the string.
So: have any holes been left here? And am I misunderstanding any of the regex above? Finally, is there any way to security-proof this without excluding ( characters? The string to be input is ideally a mathematical formula, and allowing ( would allow for manipulation of order of operations, which currently is impossible.
Evaluate the code inside a VM - see Runkit_Sandbox
Or create a parser for your math. I suggest you use the built-in tokenizer. You would need to iterate tokens and keep track of brackets, T_DNUMBER, T_LNUMBER, operators and maybe T_CONSTANT_ENCAPSED_STRING. Ignore everything else. Then you can safely evaluate the resulting expression.
A quick google search revealed this library. It does exactly what you want...
A simple example using the tokenizer:
$tokens = token_get_all("<?php {$input}");
$expr = '';
foreach($tokens as $token){
if(is_string($token)){
if(in_array($token, array('(', ')', '+', '-', '/', '*'), true))
$expr .= $token;
continue;
}
list($id, $text) = $token;
if(in_array($id, array(T_DNUMBER, T_LNUMBER)))
$expr .= $text;
}
$result = eval("<?php {$expr}");
(test)
This will only work if the input is a valid math expression. Otherwise you'll get a parse error in your eval`d code because of empty brackets and stuff like that. If you need to handle this too, then sanitize the output expression inside another loop. This should take care of the most of the invalid parts:
while(strpos($expr, '()') !== false)
$expr = str_replace('()', '', $expr);
$expr = trim($expr, '+-/*');
Matching what is allowed instead of removing some characters is the best approach here.
I see that you do not filter ` (backtick) that can be used to execute system commands. God only knows what else is also not prevented by trying to sanitize the string... No matter how many holes are found, there is no guarantee that there cannot be more.
Assuming that your language is not quite complex, it may not be that hard to implement it yourself without the use of eval.
The following code is our own attempt to answer the same sort of question:
$szCode = "whatever code you would like to submit to eval";
/* First check against language construct or instructions you don't allow such as (but not limited to) "require", "include", ..." : a simple string search will do */
if ( illegalInstructions( $szCode ) )
{
die( "ILLEGAL" );
}
/* This simple regex detects functions (spend more time on the regex to
fine-tune the function detection if needed) */
if ( preg_match_all( '/(?P<fnc>[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*) ?\(.*?\)/si',$szCode,$aFunctions,PREG_PATTERN_ORDER ) )
{
/* For each function call */
foreach( $aFunctions['fnc'] as $szFnc )
{
/* Check whether we can accept this function */
if ( ! isFunctionAllowed( $szFnc ) )
{
die( "'{$szFnc}' IS ILLEGAL" );
} /* if ( ! q_isFncAllowed( $szFnc ) ) */
}
}
/* If you got up to here ... it means that you accept the risk of evaluating
the PHP code that was submitted */
eval( $szCode );
I'm working on converting an old define()-based language/translation system to a more flexible one (probably JSON-based, but it's still open).
As part of this conversion, I will need to convert from 42 .php files with several thousand strings each to whatever format I'll be using. Some of the defined strings reference other defines or use PHP code. I don't need to keep this dynamic behaviour (it's never really dynamic anyway), but I will need to have the "current" values at time of conversion.
One define might look like this:
define('LNG_Some_string', 'Page $s of $s of our fine '.LNG_Product_name);
Since all defines have an easily recognizable 'LNG_' prefix, converting a single file is trivial. But I'd like to make a small script which handles all 42 in one run.
Ideally I'd be able to either undefine or redefine the define()'s, but I can't find a simple way of doing that. Is this at all possible?
Alternatively, what would be a good way of handling this conversion? The script will be one-off, so it doesn't need to be maintainable or fast. I just want it fully automated to avoid human error.
if speed is not important, so you can use get_defined_constants function.
$constans = get_defined_constants(true);
$myconst = array();
$myconst = $constans['user'];
$myconst will contain all constants defined by your script:-)
P.S: I'm not a good php coder, it was just a suggestion :-)
You can't undefine constants, but you can generate your new scripts by utiliising them and the constant() function:
<?php
/* presuming all the .php files are in the same directoy */
foreach (glob('/path/*.php') as $file) {
$contents = file_get_contents($file);
$matches = array();
if (!preg_match('/define\(\'LNG_(\w+)\'/', $contents, $matches) {
echo 'No defines found.';
exit;
}
$newContents = '';
include_once $file;
foreach ($matches as $match) {
$newContents .= "SOME OUTPUT USING $match AS NAME AND " . constant($match) . " TO GET VALUE";
}
file_put_contents('new_'.$file, $newContents);
}
?>
Defined constants can't be undefined. They're immutable.
Perhaps what you can do is get in right before they're defined and modify them in certain circumstances.
foreach(explode(',' $foo) as $bar) { ... }
vs
$test = explode(',' $foo);
foreach($test as $bar) { ... }
In the first example, does it explode the $foo string for each iteration or does PHP keep it in memory exploded in its own temporary variable? From an efficiency point of view, does it make sense to create the extra variable $test or are both pretty much equal?
I could make an educated guess, but let's try it out!
I figured there were three main ways to approach this.
explode and assign before entering the loop
explode within the loop, no assignment
string tokenize
My hypotheses:
probably consume more memory due to assignment
probably identical to #1 or #3, not sure which
probably both quicker and much smaller memory footprint
Approach
Here's my test script:
<?php
ini_set('memory_limit', '1024M');
$listStr = 'text';
$listStr .= str_repeat(',text', 9999999);
$timeStart = microtime(true);
/*****
* {INSERT LOOP HERE}
*/
$timeEnd = microtime(true);
$timeElapsed = $timeEnd - $timeStart;
printf("Memory used: %s kB\n", memory_get_peak_usage()/1024);
printf("Total time: %s s\n", $timeElapsed);
And here are the three versions:
1)
// explode separately
$arr = explode(',', $listStr);
foreach ($arr as $val) {}
2)
// explode inline-ly
foreach (explode(',', $listStr) as $val) {}
3)
// tokenize
$tok = strtok($listStr, ',');
while ($tok = strtok(',')) {}
Results
Conclusions
Looks like some assumptions were disproven. Don't you love science? :-)
In the big picture, any of these methods is sufficiently fast for a list of "reasonable size" (few hundred or few thousand).
If you're iterating over something huge, time difference is relatively minor but memory usage could be different by an order of magnitude!
When you explode() inline without pre-assignment, it's a fair bit slower for some reason.
Surprisingly, tokenizing is a bit slower than explicitly iterating a declared array. Working on such a small scale, I believe that's due to the call stack overhead of making a function call to strtok() every iteration. More on this below.
In terms of number of function calls, explode()ing really tops tokenizing. O(1) vs O(n)
I added a bonus to the chart where I run method 1) with a function call in the loop. I used strlen($val), thinking it would be a relatively similar execution time. That's subject to debate, but I was only trying to make a general point. (I only ran strlen($val) and ignored its output. I did not assign it to anything, for an assignment would be an additional time-cost.)
// explode separately
$arr = explode(',', $listStr);
foreach ($arr as $val) {strlen($val);}
As you can see from the results table, it then becomes the slowest method of the three.
Final thought
This is interesting to know, but my suggestion is to do whatever you feel is most readable/maintainable. Only if you're really dealing with a significantly large dataset should you be worried about these micro-optimizations.
In the first case, PHP explodes it once and keeps it in memory.
The impact of creating a different variable or the other way would be negligible. PHP Interpreter would need to maintain a pointer to a location of next item whether they are user defined or not.
From the point of memory it will not make a difference, because PHP uses the copy on write concept.
Apart from that, I personally would opt for the first option - it's a line less, but not less readable (imho!).
Efficiency in what sense? Memory management, or processor? Processor wouldn't make a difference, for memory - you can always do $foo = explode(',', $foo)
It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 12 years ago.
Locked. This question and its answers are locked because the question is off-topic but has historical significance. It is not currently accepting new answers or interactions.
I know this sounds like a point-whoring question but let me explain where I'm coming from.
Out of college I got a job at a PHP shop. I worked there for a year and a half and thought that I had learned all there was to learn about programming.
Then I got a job as a one-man internal development shop at a sizable corporation where all the work was in C#. In my commitment to the position I started reading a ton of blogs and books and quickly realized how wrong I was to think I knew everything. I learned about unit testing, dependency injection and decorator patterns, the design principle of loose coupling, the composition over inheritance debate, and so on and on and on - I am still very much absorbing it all. Needless to say my programming style has changed entirely in the last year.
Now I find myself picking up a php project doing some coding for a friend's start-up and I feel completely constrained as opposed to programming in C#. It really bothers me that all variables at a class scope have to be referred to by appending '$this->' . It annoys me that none of the IDEs that I've tried have very good intellisense and that my SimpleTest unit tests methods have to start with the word 'test'. It drives me crazy that dynamic typing keeps me from specifying implicitly which parameter type a method expects, and that you have to write a switch statement to do method overloads. I can't stand that you can't have nested namespaces and have to use the :: operator to call the base class's constructor.
Now I have no intention of starting a PHP vs C# debate, rather what I mean to say is that I'm sure there are some PHP features that I either don't know about or know about yet fail to use properly. I am set in my C# universe and having trouble seeing outside the glass bowl.
So I'm asking, what are your favorite features of PHP? What are things you can do in it that you can't or are more difficult in the .Net languages?
Documentation. The documentation gets my vote. I haven't encountered a more thorough online documentation for a programming language - everything else I have to piece together from various websites and man pages.
Arrays. Judging from the answers to this question I don't think people fully appreciate just how easy and useful Arrays in PHP are. PHP Arrays act as lists, maps, stacks and generic data structures all at the same time. Arrays are implemented in the language core and are used all over the place which results in good CPU cache locality. Perl and Python both use separate language constructs for lists and maps resulting in more copying and potentially confusing transformations.
Stream Handlers allow you to extend the "FileSystem" with logic that as far as I know is quite difficult to do in most other languages.
For example with the MS-Excel Stream handler you can create a MS Excel file in the following way:
$fp = fopen("xlsfile://tmp/test.xls", "wb");
if (!is_resource($fp)) {
die("Cannot open excel file");
}
$data= array(
array("Name" => "Bob Loblaw", "Age" => 50),
array("Name" => "Popo Jijo", "Age" => 75),
array("Name" => "Tiny Tim", "Age" => 90)
);
fwrite($fp, serialize($data));
fclose($fp);
Magic Methods are fall-through methods that get called whenever you invoke a method that doesn't exist or assign or read a property that doesn't exist, among other things.
interface AllMagicMethods {
// accessing undefined or invisible (e.g. private) properties
public function __get($fieldName);
public function __set($fieldName, $value);
public function __isset($fieldName);
public function __unset($fieldName);
// calling undefined or invisible (e.g. private) methods
public function __call($funcName, $args);
public static function __callStatic($funcName, $args); // as of PHP 5.3
// on serialize() / unserialize()
public function __sleep();
public function __wakeup();
// conversion to string (e.g. with (string) $obj, echo $obj, strlen($obj), ...)
public function __toString();
// calling the object like a function (e.g. $obj($arg, $arg2))
public function __invoke($arguments, $...);
// called on var_export()
public static function __set_state($array);
}
A C++ developer here might notice, that PHP allows overloading some operators, e.g. () or (string). Actually PHP allows overloading even more, for example the [] operator (ArrayAccess), the foreach language construct (Iterator and IteratorAggregate) and the count function (Countable).
The standard class is a neat container. I only learned about it recently.
Instead of using an array to hold serveral attributes
$person = array();
$person['name'] = 'bob';
$person['age'] = 5;
You can use a standard class
$person = new stdClass();
$person->name = 'bob';
$person->age = 5;
This is particularly helpful when accessing these variables in a string
$string = $person['name'] . ' is ' . $person['age'] . ' years old.';
// vs
$string = "$person->name is $person->age years old.";
Include files can have a return value you can assign to a variable.
// config.php
return array(
'db' => array(
'host' => 'example.org',
'user' => 'usr',
// ...
),
// ...
);
// index.php
$config = include 'config.php';
echo $config['db']['host']; // example.org
You can take advantage of the fact that the or operator has lower precedence than = to do this:
$page = (int) #$_GET['page']
or $page = 1;
If the value of the first assignment evaluates to true, the second assignment is ignored. Another example:
$record = get_record($id)
or throw new Exception("...");
__autoload() (class-) files aided by set_include_path().
In PHP5 it is now unnecessary to specify long lists of "include_once" statements when doing decent OOP.
Just define a small set of directory in which class-library files are sanely structured, and set the auto include path:
set_include_path(get_include_path() . PATH_SEPARATOR . '../libs/');`
Now the __autoload() routine:
function __autoload($classname) {
// every class is stored in a file "libs/classname.class.php"
// note: temporary alter error_reporting to prevent WARNINGS
// Do not suppress errors with a # - syntax errors will fail silently!
include_once($classname . '.class.php');
}
Now PHP will automagically include the needed files on-demand, conserving parsing time and memory.
Easiness. The greatest feature is how easy it is for new developers to sit down and write "working" scripts and understand the code.
The worst feature is how easy it is for new developers to sit down and write "working" scripts and think they understand the code.
The openness of the community surrounding PHP and the massive amounts of PHP projects available as open-source is a lot less intimidating for someone entering the development world and like you, can be a stepping stone into more mature languages.
I won't debate the technical things as many before me have but if you look at PHP as a community rather than a web language, a community that clearly embraced you when you started developing, the benefits really speak for themselves.
Variable variables and functions without a doubt!
$foo = 'bar';
$bar = 'foobar';
echo $$foo; //This outputs foobar
function bar() {
echo 'Hello world!';
}
function foobar() {
echo 'What a wonderful world!';
}
$foo(); //This outputs Hello world!
$$foo(); //This outputs What a wonderful world!
The same concept applies to object parameters ($some_object->$some_variable);
Very, very nice. Make's coding with loops and patterns very easy, and it's faster and more under control than eval (Thanx #Ross & #Joshi Spawnbrood!).t
You can use functions with a undefined number of arguments using the func_get_args().
<?php
function test() {
$args = func_get_args();
echo $args[2]; // will print 'd'
echo $args[1]; // will print 3
}
test(1,3,'d',4);
?>
I love remote files. For web development, this kind of feature is exceptionally useful.
Need to work with the contents of a web page? A simple
$fp = fopen('http://example.com');
and you've got a file handle ready to go, just like any other normal file.
Or how about reading a remote file or web page directly in to a string?
$str = file_get_contents('http://example.com/file');
The usefulness of this particular method is hard to overstate.
Want to analyze a remote image? How about doing it via FTP?
$imageInfo = getimagesize('ftp://user:password#ftp.example.com/image/name.jpg');
Almost any PHP function that works with files can work with a remote file. You can even include() or require() code files remotely this way.
strtr()
It's extremely fast, so much that you would be amazed. Internally it probably uses some crazy b-tree type structure to arrange your matches by their common prefixes. I use it with over 200 find and replace strings and it still goes through 1MB in less than 100ms. For all but trivially small strings strtr() is even significantly faster than strtolower() at doing the exact same thing, even taking character set into account. You could probably write an entire parser using successive strtr calls and it'd be faster than the usual regular expression match, figure out token type, output this or that, next regular expression kind of thing.
I was writing a text normaliser for splitting text into words, lowercasing, removing punctuation etc and strtr was my Swiss army knife, it beat the pants off regular expressions or even str_replace().
One not so well known feature of PHP is extract(), a function that unpacks an associative array into the local namespace. This probably exists for the autoglobal abormination but is very useful for templating:
function render_template($template_name, $context, $as_string=false)
{
extract($context);
if ($as_string)
ob_start();
include TEMPLATE_DIR . '/' . $template_name;
if ($as_string)
return ob_get_clean();
}
Now you can use render_template('index.html', array('foo' => 'bar')) and only $foo with the value "bar" appears in the template.
Range() isn't hidden per se, but I still see a lot of people iterating with:
for ($i=0; $i < $x; $i++) {
// code...
}
when they could be using:
foreach (range(0, 12) as $number) {
// ...
}
And you can do simple things like
foreach (range(date("Y"), date("Y")+20) as $i)
{
print "\t<option value=\"{$i}\">{$i}</option>\n";
}
PHP enabled webspace is usually less expensive than something with (asp).net.
You might call that a feature ;-)
The static keyword is useful outside of a OOP standpoint. You can quickly and easily implement 'memoization' or function caching with something as simple as:
<?php
function foo($arg1)
{
static $cache;
if( !isset($cache[md5($arg1)]) )
{
// Do the work here
$cache[md5($arg1)] = $results;
}
return $cache[md5($arg1)];
}
?>
The static keyword creates a variable that persists only within the scope of that function past the execution. This technique is great for functions that hit the database like get_all_books_by_id(...) or get_all_categories(...) that you would call more than once during a page load.
Caveat: Make sure you find out the best way to make a key for your hash, in just about every circumstance the md5(...) above is NOT a good decision (speed and output length issues), I used it for illustrative purposes. sprintf('%u', crc32(...)) or spl_object_hash(...) may be much better depending on the context.
One nice feature of PHP is the CLI. It's not so "promoted" in the documentation but if you need routine scripts / console apps, using cron + php cli is really fast to develop!
Then "and print" trick
<?php $flag and print "Blah" ?>
Will echo Blah if $flag is true. DOES NOT WORK WITH ECHO.
This is very handy in template and replace the ? : that are not really easy to read.
You can use minus character in variable names like this:
class style
{
....
function set_bg_colour($c)
{
$this->{'background-color'} = $c;
}
}
Why use it? No idea: maybe for a CSS model? Or some weird JSON you need to output. It's an odd feature :)
HEREDOC syntax is my favourite hidden feature. Always difficult to find as you can't Google for <<< but it stops you having to escape large chunks of HTML and still allows you to drop variables into the stream.
echo <<<EOM
<div id="someblock">
<img src="{$file}" />
</div>
EOM;
Probably not many know that it is possible to specify constant "variables" as default values for function parameters:
function myFunc($param1, $param2 = MY_CONST)
{
//code...
}
Strings can be used as if they were arrays:
$str = 'hell o World';
echo $str; //outputs: "hell o World"
$str[0] = 'H';
echo $str; //outputs: "Hell o World"
$str[4] = null;
echo $str; //outputs: "Hello World"
The single most useful thing about PHP code is that if I don't quite understand a function I see I can look it up by using a browser and typing:
http://php.net/function
Last month I saw the "range" function in some code. It's one of the hundreds of functions I'd managed to never use but turn out to be really useful:
http://php.net/range
That url is an alias for http://us2.php.net/manual/en/function.range.php. That simple idea, of mapping functions and keywords to urls, is awesome.
I wish other languages, frameworks, databases, operating systems has as simple a mechanism for looking up documentation.
Fast block comments
/*
die('You shall not pass!');
//*/
//*
die('You shall not pass!');
//*/
These comments allow you to toggle if a code block is commented with one character.
My list.. most of them fall more under the "hidden features" than the "favorite features" (I hope!), and not all are useful, but .. yeah.
// swap values. any number of vars works, obviously
list($a, $b) = array($b, $a);
// nested list() calls "fill" variables from multidim arrays:
$arr = array(
array('aaaa', 'bbb'),
array('cc', 'd')
);
list(list($a, $b), list($c, $d)) = $arr;
echo "$a $b $c $d"; // -> aaaa bbb cc d
// list() values to arrays
while (list($arr1[], $arr2[], $arr3[]) = mysql_fetch_row($res)) { .. }
// or get columns from a matrix
foreach($data as $row) list($col_1[], $col_2[], $col_3[]) = $row;
// abusing the ternary operator to set other variables as a side effect:
$foo = $condition ? 'Yes' . (($bar = 'right') && false) : 'No' . (($bar = 'left') && false);
// boolean False cast to string for concatenation becomes an empty string ''.
// you can also use list() but that's so boring ;-)
list($foo, $bar) = $condition ? array('Yes', 'right') : array('No', 'left');
You can nest ternary operators too, comes in handy sometimes.
// the strings' "Complex syntax" allows for *weird* stuff.
// given $i = 3, if $custom is true, set $foo to $P['size3'], else to $C['size3']:
$foo = ${$custom?'P':'C'}['size'.$i];
$foo = $custom?$P['size'.$i]:$C['size'.$i]; // does the same, but it's too long ;-)
// similarly, splitting an array $all_rows into two arrays $data0 and $data1 based
// on some field 'active' in the sub-arrays:
foreach ($all_rows as $row) ${'data'.($row['active']?1:0)}[] = $row;
// slight adaption from another answer here, I had to try out what else you could
// abuse as variable names.. turns out, way too much...
$string = 'f.> <!-? o+';
${$string} = 'asdfasf';
echo ${$string}; // -> 'asdfasf'
echo $GLOBALS['f.> <!-? o+']; // -> 'asdfasf'
// (don't do this. srsly.)
${''} = 456;
echo ${''}; // -> 456
echo $GLOBALS['']; // -> 456
// I have no idea.
Right, I'll stop for now :-)
Hmm, it's been a while..
// just discovered you can comment the hell out of php:
$q/* snarf */=/* quux */$_GET/* foo */[/* bar */'q'/* bazz */]/* yadda */;
So, just discovered you can pass any string as a method name IF you enclose it with curly brackets. You can't define any string as a method alas, but you can catch them with __call(), and process them further as needed. Hmmm....
class foo {
function __call($func, $args) {
eval ($func);
}
}
$x = new foo;
$x->{'foreach(range(1, 10) as $i) {echo $i."\n";}'}();
Found this little gem in Reddit comments:
$foo = 'abcde';
$strlen = 'strlen';
echo "$foo is {$strlen($foo)} characters long."; // "abcde is 5 characters long."
You can't call functions inside {} directly like this, but you can use variables-holding-the-function-name and call those! (*and* you can use variable variables on it, too)
Array manipulation.
Tons of tools for working with and manipulating arrays. It may not be unique to PHP, but I've never worked with a language that made it so easy.
I'm a bit like you, I've coded PHP for over 8 years. I had to take a .NET/C# course about a year ago and I really enjoyed the C# language (hated ASP.NET) but it made me a better PHP developer.
PHP as a language is pretty poor, but, I'm extremely quick with it and the LAMP stack is awesome. The end product far outweighs the sum of the parts.
That said, in answer to your question:
http://uk.php.net/SPL
I love the SPL, the collection class in C# was something that I liked as soon as I started with it. Now I can have my cake and eat it.
Andrew
I'm a little surprised no-one has mentioned it yet, but one of my favourite tricks with arrays is using the plus operator. It is a little bit like array_merge() but a little simpler. I've found it's usually what I want. In effect, it takes all the entries in the RHS and makes them appear in a copy of the LHS, overwriting as necessary (i.e. it's non-commutative). Very useful for starting with a "default" array and adding some real values all in one hit, whilst leaving default values in place for values not provided.
Code sample requested:
// Set the normal defaults.
$control_defaults = array( 'type' => 'text', 'size' => 30 );
// ... many lines later ...
$control_5 = $control_defaults + array( 'name' => 'surname', 'size' => 40 );
// This is the same as:
// $control_5 = array( 'type' => 'text', 'name' => 'surname', 'size' => 40 );
Here's one, I like how setting default values on function parameters that aren't supplied is much easier:
function MyMethod($VarICareAbout, $VarIDontCareAbout = 'yippie') { }
Quick and dirty is the default.
The language is filled with useful shortcuts, This makes PHP the perfect candidate for (small) projects that have a short time-to-market.
Not that clean PHP code is impossible, it just takes some extra effort and experience.
But I love PHP because it lets me express what I want without typing an essay.
PHP:
if (preg_match("/cat/","one cat")) {
// do something
}
JAVA:
import java.util.regex.*;
Pattern p = Pattern.compile("cat");
Matcher m = p.matcher("one cat")
if (m.find()) {
// do something
}
And yes, that includes not typing Int.