Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I need some PHP code to convert some PHP into JS.
functionality - I'm using common PHP functions from php.js
syntax - ???
The issue is converting the syntax. I don't need full PHP syntax, mind you; no need for supporting class definitions/declarations. Here's a small checklist of what needs conversion:
"." should be "+" (string concat)
"->" should be "." (object operator)
"::" should be "." (class operator - not really required)
Please note that the resulting code is pretty much independent of the PHP environment, so no "what if it uses a PHP class?".
I'm not asking for full code, just a tip on the right direction to this kind of conversion; I was thinking about employing a state machine/engine.
If you're curious as to why I'm pushing code to the user side: I need a dynamic way to change visibility of certain elements given certain conditions. My plan is to do this without having to execute this code server side and having unnecessary ajax calls.
Edit: Look people. I know not using AJAX sounds ludicrous to you but the world doesn't work on hype and nice-sounding design conditions (=ajax). I simply can't afford each single user polling my server 5 to 10 times per second just for my server to return a "yes" or "no" answer. Keep in mind that switching is asynchronous, and I can't buffer the AJAX calls.
Edit 2: I am sure what I'm doing is the best way in my situation. There is no "possibly better" way, so quit posting non-constructive comments. I can't get into any more detail than I have so already. The conversion from PHP code to JS is simply a matter of shortening user input; we only need one expression, then convert it to whichever language is necessary (in this particular case, from PHP to JS). The conditions on how this works will not change regardless if I describe the system down to the API specs, and inundating the topic with useless (for you) prototype docs will not help at all.
Also, for those thinking this idea came after waking up form some dream; know this has been reviewed between technical development and QA, so please do not deviate into inexistent design issues.
Edit 3: Examples (original PHP code and expected output):
(original) -- (converted)
5=="test" -- 5=="test"
'$'.(func(12)*10) -- '$'+(func(12)*10)
Fields::count()==5 -- Fields.count()==5
$this->id==5 -- this.id==5
About the last example, don't worry about context/scope, it is correct. Also note that the expressions may look weird; this is because they are expression; a single line of code that must return a value, which explains the absence of an EOL (;) and the multiple use of returning a boolean value. (exotic stuff like backtick operator execution, PHP tags, echo, die, list, etc.. left out on purpose)
Okay, let me take a stab at this one...
Screw regexes. I love them, but there's a better way, and it's built in. Check out token_get_all(). It will parse PHP source as a string and return a list of the very same tokens that PHP itself uses (including the beloved T_PAAMAYIM_NEKUDOTAYIM). You can then completely reconstruct the source of the script, one token at a time, translating it into Javascript syntax along the way.
[charles#teh ~]$ php --interactive
Interactive shell
php > print_r(token_get_all('<?php class Foo { public function bar() { echo "Yikes!"; } } $f = new Foo(); $f->bar(); ?>'));
Array
(
[0] => Array
(
[0] => 368
[1] => <?php
[2] => 1
)
[1] => Array
(
[0] => 353
[1] => class
[2] => 1
)
[2] => Array
(
[0] => 371
[1] =>
[2] => 1
)
[3] => Array
(
[0] => 307
[1] => Foo
[2] => 1
)
...
While this may be a bit overkill, it also uses the same parsing rules PHP uses, and should therefore be less of a long-term pain than regular expressions. It also gives you the flexibility to detect features that can't be translated (i.e. things that php-js doesn't support) and reject the translation and/or work around the problem.
Also, you still haven't told us what you're doing and why you're doing it. There are still probably more accurate, useful answers available. Help us help you by giving us more information.
You believe polling to be unrealistic due to an expected stupidly high number of requests per second. Why are you expecting that number? What does your application do that would cause such conditions?
Why do you want to translate PHP code rather than writing specific Javascript? You're just manipulating page contents a bit, why do you need PHP code to make that decision?
Language translation is probably the least simple solution to this problem, and is therefore an amazingly awful idea. It couldn't have been arrived at as the first option. What are your other options, and why have they been ruled out?
Have you tried Harmony Framework?
Here's the quick and dirty solution I came up with, written in under 20 minutes (probably lots of bugs), but it looks like it works.
function convertPhpToJs($php){
$php=str_split($php,1); $js='';
$str=''; // state; either empty or a quote character
$strs=array('\'','`','"'); // string quotes; single double and backtick
$nums=array('0','1','2','3','4','5','6','7','8','9'); // numerals
$wsps=array(chr(9),chr(10),chr(13),chr(32)); // remove whitespace from code
foreach($php as $n=>$c){
$p=isset($php[$n-1])?$php[$n-1]:'';
$f=isset($php[$n+1])?$php[$n+1]:'';
if($str!='' && $str!=$c){ $js.=$c; continue; } // in a string
if($str=='' && in_array($c,$strs)){ $str=$c; $js.=$c; continue; } // starting a string
if($str!='' && $str==$c){ $str=''; $js.=$c; continue; } // ending a string
// else, it is inside code
if($c=='$')continue; // filter out perl-style variable names
if($c==':' && $f==':'){ $js.='.'; continue; } // replace 1st of :: to .
if($p==':' && $c==':')continue; // filter out 2nd char of ::
if($c=='-' && $f=='>'){ $js.='.'; continue; } // replace 1st of -> to .
if($p=='-' && $c=='>')continue; // filter out 2nd char of ->
if($c=='.' && (!in_array($p,$nums) || !in_array($f,$nums))){ $js.='+'; continue; } // replace string concat op . to +
if(in_array($c,$wsps))continue; // filter out whitespace
$js.=$c;
}
return $js;
}
The following:
$window->alert("$".Math::round(450/10));
Converted to:
window.alert("$"+Math.round(450/10));
Edit: Can't believe all the fuss this question caused compared to the time taken.
Feel free to criticize at will. I don't actually like it much personally.
I wrote a tool called php2js that can automatically convert PHP code to javascript. It is not perfect, but supports the most common PHP functionality including classes, inheritance, arrays, etc, etc. It also includes and knows about php.js, so code written with php's standard library functions may "just work".
Maybe you will find it useful.
Im created tool PHP-to-JavaScript for converting PHP code to JavaScript. Its support:
Namespaces,use
Class, abstract class extends and interfaces
constants and define
Exceptions and catch
list()
magic methods __get __set and __call
and more
Related
I'm trying to write more functional code in PHP without any helper libraries.
I need to return some JSON that includes the results of a transformed array AND the count of that array (for convenience on the data consumer end). Since you're not supposed to use variables in FP, I'm stumped on how to get the count of the array without recalculating/remapping the array.
Here's an example of what my code currently looks like:
$duplicates = array_filter( get_results(), 'find_duplicates' );
send_json( array(
"duplicates" => $duplicates,
"numDuplicates" => count( $duplicates )
) );
How can I do the same without storing the results of the filter in a temporary variable to avoid running array_filter() twice?
But first, acknowledge the following...
"Since you're not supposed to use variables in FP..." – that's a ludicrous understanding of functional programming. Variables are used constantly in functional programs. I'm guessing you saw point-free functional programs and then imagined that every program can be expressed in such a way...
the receiver of the JSON could easily get the number of duplicates using JSON.parse(json).duplicates.length because every Array in JavaScript has a length property – it's arguably silly to attach a numDuplicates in the first place. Anyway, let's assume your consumer has a specific API that requires the numDuplicates field...
functional programming is concerned with things like function purity – maybe you've simplified your code in your post (which is bad; don't do that) or that is in fact your actual code. In such a case, get_results() and send_json functions are impure; send_json has an obvious (but unknown) side effect (the return value is not used) — You ask for a functional solution but you have other outstanding non-functional code... so...
There's nothing wrong with the code you have. Sometimes removing a point (variable, or argument), it hurts the readability of the code. In your case, this code is perfectly legible. It is at this point that I feel you're only trying to shorten the code or make it more clever. Your intention is to improve it, but I think you'd actually harm it in this case.
What if I told you...
a variable assignment can be replaced with a lambda? 0_0
(function ($duplicates) {
send_json([
'duplicates' => $duplicates,
'numDuplicates' => count($duplicates)
});
}) (array_filter(get_results(), 'find_duplicates'));
But that made the code longer.. and there's added abstraction which hurts readability T_T In this case, using a normal variable assignment (as in your original code) would've been much better
Combinators
OK, so what if you had some combinators at your disposal to massage the data into the desired shape?
function apply (...$xs) {
return function ($f) use ($xs) {
return call_user_func($f, ...$xs);
};
}
function identity ($x) { return $x; }
// hey look, mom! no points!
send_json(
array_combine(
['duplicates', 'numDuplicates'],
array_map(
apply(
array_filter(get_results(), 'find_duplicates')),
['identity', 'count'])));
Did we achieve anything other than writing the weirdest PHP you or anyone else has probably seen? Not to mention, the input is strangely nested in the middle of the expression...
remarks
I'm nearly certain that you'll be disappointed with this answer (or disagree with me), but I'm also pretty confident that you're not sure what you're looking for. A guess: you saw functional programming that "doesn't use variables" and assumed that's how all programs can and should be written; but that's just not the case. Sometimes using a variable or two can dramatically improve the readability of a given expression.
Anyway, all of this is truly beside the point because attaching numDuplicates is arguably an anti-pattern in JSON anyway (point #2 above).
What is the best way to debug an array so that you can see what values are being stored and in what keys in the array they are being stored at? Also how do you make it so that it's easier to look at visually so that you don't have to keep looking through the array for the key and it's value in the one line print_r() function?
EDIT:
I now realize that print_r() is not the only solution to debugging arrays. So if you have alternate solutions that would be lovely as well to learn more about debugging.
EDIT2:
Ayesh K, ITroubs and Robert Rozas have mentioned both Krumo and Kint this far, if you have others feel free to post them. Also thanks to Raveren for writing Kint!
Every PHP developer should have a function for this. My function is below:
function r($var){
echo '<pre>';
print_r($var);
echo '</pre>';
}
To nicely print data, just call r($data);. If you want more detail, you could use this function:
function d($var){
echo '<pre>';
var_dump($var);
echo '</pre>';
}
here's mine...
demo: http://o-0.me/dump_r/
repo: https://github.com/leeoniya/dump_r.php
composer: https://packagist.org/packages/leeoniya/dump-r
you can restyle it via css if needed.
Everyone suggests print_r which is in core and works really well.
But when it comes to view a large array, print_r() drives me nuts narrowing down the output.
Give a try to krumo.
It nicely prints the array with visual formatting, click-expand and it also gives you the exact array key call that you can simply copy and paste.
<?php
krumo($my_array);
?>
Itroubs mentioned Kint as a better alternative to Krumo. (Thanks ITroubs!)
I use var_dump....now if you want some more, check out this site:
http://raveren.github.io/kint/
and
http://krumo.sourceforge.net/
The best practice to visually see the values/keys in an array is the following:
echo "<pre>".print_r($array,TRUE)."</pre>";
The true is required as it changes it into a string, the output will be:
array(
key1 => value,
key2 => value,
...
)
Quick solution: Open the source code of the page, and you'll see print_r's output in several lines and perfectly indented.
print_r is not one lined (it uses \n as new line, not <br>). Add a <pre>...</pre> around it to show the multiple lines.
print_r() uses \n as its line delimiter. Use <pre> tags or view the page's source code to make it look right. (on Windows, Linux works with \n)
You can either look source code or use var_dump() or print_r() with <pre>...</pre>
I personally, never liked all this fancy stuff, i use print_r() because it's not overwhelming and it gives enough information.
Here is mine:
if(isset($_SERVER['HTTP_USER_AGENT']) && $_SERVER['HTTP_USER_AGENT'] == 'Debug')
{
echo '<strong><i>FILE : </i></strong>'.__FILE__.'<strong> <i>LINE : </i></strong>'.__LINE__.'<pre>';
print_r($var);
echo '</pre>';
die;
}
This if statement is to ensure that other people don't see what you've printed.
There is a good add-on for Mozila-Firefox and Google Chrome called "user agent switcher", where you can create your custom user agents. So I create a user agent called "Debug", and when I'm working, I change the user agent.
If I use default user agent nothing will happen and the page wont die;, only you and people who also change the user agent to "Debug" will see the printed variable. This is helpful if you want to debug a problem in a production environment, and you don't want the page to die; and it is also good if other people are also working on the project and you don't want to interrupt them by killing the page.
Then I echo out the current File and Line, this is helpful when you work in a framework or CMS or any other big project with thousands of files and folders, and while debugging, if you might forget where you've typed die; or exit; and you need to remember where you've been and which variables you have printed.
I use the NetBeans IDE for PHP development, I have a macro set up so when you select a variable and use it, it will paste this debugging tool to the text editor and put the selection inside a print_r(); function. If you also use NetBeans, you can use this macro:
cut-to-clipboard
"if(isset($_SERVER['HTTP_USER_AGENT']) && $_SERVER['HTTP_USER_AGENT'] == 'Debug')"
insert-break
"{"
insert-break
"echo '<strong><i>FILE : </i></strong>'.__FILE__.'<strong> <i>LINE :</i></strong>'.__LINE__.'<pre>';"
insert-break
"print_r("
paste-from-clipboard
remove-line-begin
");"
insert-break
"echo '</pre>';"
insert-break
"die;"
You just need to select the $variable and use the macro.
To be honest, I'm surprised that print_r() (print human-readable). There are three native functions which each have their advantages and disadvantages in printing data to a document. As mentioned elsewhere on the page, wrapping your output in <pre> ... </pre> tags will be very beneficial in respecting newlines and tabbing when printing to an html document.
The truth is that ALL php developers, from newbie to hobbyist to professional to grand wizard level 999, need to have the following techniques in their toolbox.
Here is a non-exhaustive demo which exposes some of the differences.
var_export() is the format that I use most often. This function wraps strings in single quotes. This is important in identifying trailing whitespace characters and differentiating numeric types versus string types. To maintain the integrity of the output data and permit instant portability of the data into a runnable context, single quotes and backslashes are escaped -- don't let this trip you up.
print_r() is probably my least-used and the least-informative function when data needs to be inspect. It does not wrap strings in any kind of delimiting character so you will not be able to eyeball invisible characters. It will not escape backslashes, single quotes, or double quotes. It wraps keys in square braces which may cause confusion if your keys contain square braces originally.
var_dump() is uniquely powerful in that it expresses data types AND the byte count for strings. This is hands-down the best tool when there is a risk that you might have unexpected multibyte characters interfering with the success/stability of your script.
Depending on your php version and which function you use, you may see differing values with same input data. Pay careful attention to float values.
debug_zval_dump() very much resembles the output of var_dump(), but also includes a refcount. This native function is not likely to provide any additional benefit relating to "debugging an array".
There are also non-native tools which may be of interest (most of which I've never bothered to use). If you are using a framework, Laravel for instance, offers dd() (dump and die) as a diagnostic helper method. Some devs love the collapsed/expandable styling of this tool, but other devs loudly voice their annoyance at the tedious clicking that is necessary to expose nested levels of data.
As a sideways approach to printing iterable data, you could entertain the idea of echoing a json-encoded string with the JSON_PRETTY_PRINT. This may reveal some things that could cause trouble like multibyte and whitespace characters, but don't forget that this is literally "encoding" the data. In other words, it is converting data from one form to another and it will mutate certain occurrences in the process. Like var_export(), a json encoded string is an excellent form to maintain data integrity when it needs to be tranferred from one place to another (like from your project to your Stack Overflow question!).
I am thinking about how one would go about creating a PHP equivalent for a couple of libraries I found for CSS and JS.
One is Less CSS which is a dynamic stylesheet language. The basic idea behind Less CSS is that it allows you to create more dynamic CSS rules containing entities that "regular" CSS does not support such as mixins, functions etc and then the final Less CSS compiles those syntax into regular CSS.
Another interesting JS library which behaves in a (kind of) similar pattern is CoffeeScript where you can write "tidier & simpler" code which then gets compiled into regular Javascript.
How would one go about creating a simple similar interface for PHP? Just as a proof of concept; I am only trying to learn stuff. Lets just take a simple use case of extending classes.
class a
{
function a_test()
{
echo "This is test in a ";
}
}
class b extends a
{
function b_test()
{
parent::a_test();
echo "This is test in b";
}
}
$b = new b();
$b->b_test();
Suppose I want to let the user write class b as (just for the example):
class b[a] //would mean b extends a
{
function b_test()
{
[a_test] //would mean parent::a_test()
echo "This is test in b";
}
}
And let them later have that code "resolve" to regular PHP (Usually by running a separate command/process I would believe). My question is how would I go about creating something like this. Can it be done in PHP, would I require to use something like C/C++. How should I approach this problem if I were to go at it? Are there any resources online? Any pointers are deeply appreciated!
Language transcoders are not as easy as one might think.
The example you gave can be implemented very easily with a preg_replace that looks for class definitions and replaces [a] with extends a.
But more complex features need a transcoder which is a suite of smaller logical pieces of code.
In most programmer jargon people incorrectly call transcoders compilers but the difference between compilers and transcoders is that compilers read source code and output raw binary machine code while transcoders read source code and output (a different) source code.
The PHP (or JavaScript) runtime for example is neither compiler nor transcoder, it's an interpreter.
But enough about jargon let's talk about transcoders:
To build a transcoder you must first build a tokenizer, it breaks apart the source code into tokens, meaning that if it sees an entire word such as 'class' or the name of a class or 'function' or the name of a function, it captures that word and considers it a token. When it encounters another token such as an opening round bracket or an opening brace or a square bracket etc. it considers that another token.
Luckily all of the recognized tokens available in PHP are already easily scanned by token_get_all which is a function PHP is bundled with. You may have some trouble because PHP assumes some things about how you use symbols but all in all you can make use of this function.
The tokenizer creates a flat list of all the tokens it finds and gives it to the parser.
The parser is the second phase of your transcoder, it reads the list of tokens and decides stuff like "if token[0] is a class and token[1] is a name_value then we have a class" etc.. after running through the entire list of tokens we should have an abstract syntax tree.
The abstract syntax tree is a structure that symbolically retains only the relevant information about a the source code.
$ast = array(
'my_derived_class' => array(
'implements' => array(
'my_interface_1',
'my_interface_2',
'my_interface_3'),
'extends' => 'my_base_class',
'members' => array(
'my_property_name' => 'my_default_value',
'my_method_name' => array( /* ... */ )
)
)
);
After you get an abstract syntax tree you need to walk through it and output the destination source code.
The real tricky part is the parser which (depending on the complexity of the language you are parsing) may need a backtracking algorithm or some other form of pattern matching to differentiate similar cases against one another.
I recommend reading about this in Terence Parr' book http://pragprog.com/book/tpdsl/language-implementation-patterns which describes in detail the design patterns needed to write a transcoder.
In Terrence' book you'll find out why some languages such as HTML or CSS are much simpler (structurally) than PHP or JavaScript and how that relates the complexity of the language parser.
What is the benefit of using multiple steps to test variables:
$VarLength = strlen($message);
if ($VarLength > 10)
echo "Over Ten";
...versus just pushing the whole process into one if statement:
if ( strlen($message) > 10 )
echo "Over Ten";
I'm wondering if the benefits go beyond code style, and the ability to re-use the results of the (in the example above) strlen result.
Your question is not really possible to answer technically, so this is more a comment than an answer.
Benefits beyond code-style and re-use of the result is when you change the code.
You might want to replace the strlen() function with some other function but you don't want to edit the line with the if clause while you do so. E.g. to prevent errors or side-effects. That could be a benefit, however it depends on code-style somehow. So as you exclude coding style from your question, it makes it hard to answer as that domain touches a lot how you can/should/would/want/must write code.
If the result of a function will be used multiple times, it should be cached in a variable so as to obviate the need to waste resources to re-calculate its result.
If the function result won't be re-used, it can simply be a matter of code readability to clearly delineate what's happening by storing the function return value in a variable before using it in an if condition.
Also, in terms of readability, you should always use curly braces even when not mandated by PHP syntax rules as #AlexHowansky mentions.
Most of it is in the code style. In terms of rapidity of the results, it doesn't change much. If you are using $varLenght more then once, then you are saving the call to the function to obtain the length. But even that, the time difference is extremely minimal (I would even like to say unnoticable).
But: When developping any applications, you have to keep in mind that you might not be the only one making changes to it down the road, or you might not be as fresh and up to date with the exact program you are writing. Therefore, the cleaner the code, the easier it is in terms of maintenance, and THAT'S where you save a lot of time down the road.
Best Practice dictates that functions be called minimally. In your case the practice doesn't violate the rule, but it is not uncommon to find code like:
if ( strlen($message) > 100 )
echo "Over Ten";
else if ( strlen($message) > 20 )
echo "Over Ten";
else if ( strlen($message) > 10 )
echo "Over Ten";
...
A common prevention is to always assign function results to a variable for consistency.
I wouldn't say there is any benefit apart from the re-use case you've already mentioned. Your latter case is more readable, probably faster, and probably less memory-intensive. I would however strongly recommend always using braces, even when your conditional is only one line:
if (condition) {
statement;
}
This function returned 524320 for one my classes. If I run it through getModifierNames, it tells me:
>> Reflection::getModifierNames(524320)
array (
0 => 'abstract',
)
Which is correct, but 524320 isn't a power of 2, so it must have some other flags? Actually, if we look at it's binary representation, 10100111 it looks like it has 5 flags set. So what are the other 4, and where can I find a list of all of them?
Edit: Now I'm confused... the representation is actually 10000000000000100000, according to this. Which makes sense, because that corresponds to "explicit abstract class". Oh... I bet this was an overflow issue now that I'm thinking about...must investigate a bit more.
See the ZEND_ACC_* constants in http://lxr.php.net/xref/PHP_TRUNK/Zend/zend_compile.h#144
Mind that some of these are internal and are not exported in anyway to userspace. The ones exported to userspace ones can be found in http://php.net/manual/en/class.reflectionmethod.php and other classes.