Home >Backend Development >PHP Tutorial >Comprehensive explanation of PHP website design issues_PHP tutorial
php is embarrassing. It was so broken, but amateurs who were trained to do it praised it. PHP was doing some trivial remedial measures, but I chose to forget about it.
Foreword
I have a weird temper. I complain about a lot of things. I don't like most technology on this planet.
Not only was PHP awkward to use, it was either not suitable for what I wanted, not the most satisfactory, or contrary to my beliefs. I can tell you all the good ways I want to avoid and all the bad ways I like about a language. Go ahead and ask! The conversation will be fun!
PHP is the only exception. Almost everything that PHP abstracts is fragmented. Including languages, frameworks, and the entire ecosystem is in a mess. I can barely list the swearing alone because it's broken all over. Every time I try to compile a tangled list of PHP complaints, I get sidetracked by trivial details, and the deeper I dig, the more shocking things I find.
php is embarrassing. It was so broken, but amateurs who were trained to do it praised it. PHP was doing some trivial remedial measures, but I chose to forget about it.
But I have to rid my system of this stuff, that’s it, this is my last try.
Make a metaphor
I just casually complained to Mel, but she insisted that I publish it.
I can’t even tell what’s wrong with PHP, because – it’s fine. Think about it like you have a, um, toolbox. A bunch of tools. Looks okay, standard stuff.
You pull out the screw and it has three weird heads. OK, well, this isn't going to be very useful to you, but you guess it will be someday.
You took out the hammer and were shocked. There were sharp claws on both sides. But it still works, I mean, you can hit it diagonally with the middle of both ends.
You take out the vises, but they don’t have serrated sides. The surface is flat and smooth. It's not that useful, but it still works, so that's okay.
You can continue. The contents of the toolbox are weird and iffy, but not worthless. Overall there is no big problem; its tools are all complete.
Now, imagine there are many carpenters using these tools and they say to you: "What's wrong with these tools? We've all used them and they work great!". The craftsmen show you the house they built, with each door being pentagonal and the roof being curved. You knock on the front door and it falls inward, and they complain that you broke their door down.
This is the problem with PHP.
Position
I think the following qualities are important to a language's productivity and usability, and PHP undermines them on a large scale. If you don't agree with any of this, well, I can't imagine we'll ever agree.
A language must be predictable. It is a medium that reflects human thoughts to computer execution, so the key is that human beings' understanding of the program must actually be correct.
Language must be consistent. Similar things should look similar, and different things should look different. Once you learn part of the language, you should be able to easily understand the rest.
Language must be concise. New languages should inherit less bad form from older languages. (We can also write machine code.) New languages should certainly try to avoid weaving in new, proprietary forms.
Language must be reliable. Language is a tool for solving problems; introducing new problems should be avoided as much as possible. Any "trap" will be a massive distraction.
The language must be debuggable. When something goes wrong, the programmer has to fix it, and we need to get the help we want.
My position is:
PHP is full of surprises: mysql_real_escape_string, E_ACTUALLY_ALL
PHP inconsistency: strpos, str_rot13
PHP requires special form: error-checkingaroundCAPIcalls, ===
PHP weird: ==. for($fooas&$bar)
PHP is obscure: no stack traces or fatalities by default, complex error reporting
I can’t explain why it falls into these categories for a single question, otherwise it will be endless. I believe readers will think for themselves.
Stop talking about these things with me
I know many favorable arguments. I hear a lot of counter-arguments as well. All this will do is bring the conversation to an immediate halt. Stop giving me this shit, please.
Don’t talk to me about “good developers can write good code in any language”, or bad developers. .Bah bah bah. This makes no sense. A good craftsman can use a stone or a hammer to drive a nail, but how many craftsmen have you seen using stone? One of the criteria for being a good developer is to be good at choosing tools.
Don’t tell me it’s the developer’s job to memorize thousands of exceptions and quirks. Yes, this is necessary in any system because computers are stupid. This does not mean that the system can accept crazy amounts without an upper limit. PHP only has exceptions, which is not enough. Once you are wrestling with the language, you have to spend more effort to actually write the program. My tools don't actively help me create apps.
Don’t tell me “that’s how CAPI works”. What is the purpose of high-level languages on the planet, when all they have to offer are some string helper functions and a bunch of wrappers for C? If so, use C! There's even CGI for it Library.
Don’t talk to me about “you deserve it for doing weird things”. If two properties exist, someday, someone will find a reason to use them together. Again, this is not C; there is no specification here, no "undefined behavior" required here.
Stop talking to me about Facebook and Wikipedia using PHP. I already knew it! They can also be written in Brainfuck, but as long as they are smart enough and keep tinkering with these things, they can always overcome the platform problems. As we all know, development time could be cut in half or doubled if written in other languages; there is no point in pulling out these figures alone.
God forbid, don’t talk to me about anything anymore! If the points listed don’t hurt your PHP opinions, it doesn’t matter, so please stop making meaningless arguments online and continue to develop cool and cool sites to prove it. I was wrong.
Let me tell you secretly: I like Python very much. I am also happy to say things about it that you don’t like to hear, if you really want to. I'm not asking for it to be perfect; I'm just trying to capitalize on the strengths and avoid the weaknesses and summarize the best of what I want.
PHP
Language core
CPAN is called "Perl's standard library". This doesn't say much about Perl's standard library, but it captures the idea that a strong core can build powerful things.
Basic principles
PHP was originally designed clearly for non-programmers (by implication, non-professional programs); the roots have been difficult to break away from. Dialogue culled from the PHP 2.0 documentation:
Once you start distinguishing different operators for each type, the language starts to get complicated. For example, you can't use '==' for strings, you must now use 'eq'. I don't see this, especially with scripting languages like PHP, most of which are quite simple and most of the time, as a non-programmer, you just want a language that contains a small amount of basic logic syntax without paying too much Learning curve.
PHP does whatever it takes to keep moving forward. Anything is better than nothing.
This is not a correct design principle. Early PHP was influenced by Perl; a large number of standard libraries referenced C and used "out" parameters; the OO part was designed like C++ and Java.
PHP draws a lot of inspiration from other languages, but it is still difficult to understand for those who are familiar with other languages. (int) looks like C, but int doesn't exist. Namespace usage. The new array syntax uses [key=>value], which is different from the way any other language defines hash literals.
Weak typing (i.e. silent automatic conversion between strings/mumbers/etc.) is so complex.
A small number of new features are implemented with new syntax; most work is done through functions or things that look like functions. In addition to class support, this of course requires new operators and keywords.
The problems listed on this page have official solutions - if you want to help Zend fix their open source programming language.
The road is long and the journey is long. Consider the following code, culled from somewhere in the PHP documentation.
@fopen('http://example.com/not-existing-file', 'r');
What will it do?
If PHP is compiled with --disable-url-fopen-wrapper, it will not work. (The documentation doesn't say, what does "not working" mean; returns null, throws an exception?)
Note that this has been removed in PHP5.2.5.
It will not work if allow_url_fopen is disabled in php.ini. (Why? No way of knowing.)
Since @, warnings for non-existentfile will not be printed.
But if scream.enabled is set in php.ini, it will print again.
Or if you use ini_set to manually set scream.enabled.
But, if the error_reporting level is not set, it is different.
If printed, the precise destination depends on display_errors, again in php.ini. or ini_set.
I can't tell you the behavior of this function call without looking at the compile-time flags, server-side configuration, and configuration in my program. These are built-in behaviors.
The language is full of global and latent states. mbstring uses global character encoding. Something like func_get_arg looks like a normal function, but only operates on the currently executing function. Error/exception handling is global by default. register_tick_function sets a global function to run every tick (hook?) - what?!
There is no thread support. (Not surprising, given above.) This, coupled with the lack of built-in fork (mentioned below), makes parallel programming extremely difficult.
Certain parts of PHP will generate error codes in practice.
json_decode returns null for incorrect input, although null is also a legal object for JSON decoding - this function is extremely unreliable unless you call json_last_error after each use.
Array_search, strpos, and other similar functions return 0 if found at position 0, but not found otherwise. Will return false
Let’s expand on the last part a little bit.
In C, functions such as strpos return -1 if not found. If you don't check for this and try to use it with subscripts, you'll probably hit garbage memory and your program will crash. (Maybe, it's C. Who knows. I'm sure there are at least tools to deal with it)
By the way, in Python, the equivalent .index method will throw an exception if the element is not found. If you don't check this situation, the program will crash.
In PHP, this function returns false. If you use FALSE as a subscript, or use it for other things, PHP will silently convert it to 0, except for === comparisons. The program will not crash; it will execute the wrong logic without any warning unless you remember to include the correct boilerplate handling code in every place where strpos and other similar functions are used.
This really sucks! Programming languages are just tools; they serve me. Here, PHP has laid a trap for me, waiting for me to jump in, and I have to always be wary of these boring string operations and equality comparisons. PHP is a minefield.
I have heard many stories about the PHP parser, its developers come from all over the world. There are people who are engaged in PHP core development, there are people who debug PHP core, and there are also people who have communicated with core developers. No story is appreciated.
So I have to insert a sentence here, because it bears repeating: PHP is a community of amateurs. Very few people design it, work for it, or very few people know what they are doing. (Oh, dear reader, you are of course the ultimate exception!) Those who grow up and want to move to other platforms bring the average of the entire community down. This, right here, is PHP's biggest problem: absolute blindness leading to blindness.
Okay, let’s come back and face reality.
Operator
== Not useful.
"foo"==TRUE, and "foo"==0...but, of course, TRUE!=0.
== will convert both sides to numbers if possible, which means it will be converted to floats if possible. So large hexadecimal strings (eg, passwordhashes) may occasionally compare to true even though they are not the same. Even JavaScript doesn't do this.
For some reason, "6" == "6", "4.2" == "4.20", and "133" == "0133". But note that 133!=0133, because 0133 is octal.
=== compares values and types...except for objects, which is true only if both sides are actually the same object! For objects, == compares values (or each property) and types, which again === compares anything that is not Behavior of object types. Is it fun?
Comparing size is not much better.
Even the behavior is inconsistent: NULL<-1, and NULL==0. The sorting is also therefore indeterminate; it depends on the order of the algorithm that compares elements in the sorting.
The comparison operators attempt to sort the array in two different ways: first by length and then by element. If they have the same number of elements but different keys, they are not comparable.
Object comparisons do more than other comparisons... except those that are neither less than nor greater than.
For type-safe == comparisons, we have ===. For type-safe < comparison, we have... nothing. "123"<"0124", usually, no matter how you do it. Type casting doesn't help either.
Although the above move is crazy, it explicitly rejects Perl’s string paris and arithmetic operators. PHP does not overload +. + is just the usual +. is the usual connector.
[]The subscript operator can also be spelled {}.
[] can be used for any variable, not just strings and arrays. It returns null with no error warning.
[] can only get a single element.
foo()[0] is a syntax error. (Fixed in PHP5.4)
Unlike similar operators (literally) in any other language, ?: is left associative. Therefore:
$arg = 'T';
$vehicle = ( ( $arg == 'B' ) ? 'bus' :
( $arg == 'A' ) ? 'airplane' :
( $arg == 'T' ) ? 'train' :
( $arg == 'C' ) ? 'car' :
( $arg == 'H' ) ? 'horse' :
'feet' );
echo $vehicle;
Print horse.
Variables
Cannot declare variable. Variables that do not exist will be created with a null value when used for the first time.
Global variables need to be declared globally before they are used. This is a natural consequence of the above, so it's a perfect reason, but without an explicit declaration, the global variable can't even be read - PHP will silently create a local variable with the same name in its place. I haven't seen other languages handle scope issues in a similar way.
No citations. PHP's so-called reference is a true alias; this is undoubtedly a step backward, unlike Perl's reference, and there is no object identifier passing like in Python.
There is no obvious way to detect and dereference.
“References” make variables unique in the language. PHP is dynamically typed, so variables are generally untyped...except for references, which modify function definitions, variable syntax, and assignments. Once a variable is referenced (which can happen anywhere), it remains a reference. There is no obvious way to detect the variable value required for dereferencing.
Okay, I lied. Some "SPLtypes" also work on variables: $x=newSplBool(true);$x="foo"; will fail. It's a bit like static typing, see for yourself.
Areferencecanbetakentoakeythatdoesn’texistwithinanundefinedvariable(whichbecomesanarray). Usinganon-existentarraynormallyissuesanoice,butthisdoesnot.
Constants defined through functions are called takingastrings; before this, they did not exist. (This may actually be copying Perl's behavior with constants.)
Variable names are case-sensitive. Function and class names are not. It would be weird to use camelCase for methods.
Structure
Array() and several similar structures are not functions. $func="array";$func(); doesn't work.
Array unpacking can be completed using the list($a,$b)=… operation. list() is a function-like syntax, just like an array. I don't know why there isn't a real dedicated syntax, and I don't know why the names are so confusing.
(int) is obviously designed to be like C, but it is not a separate tag; there is nothing called int in the language. Try this: var_dump(int) doesn't work, it throws a parse error , because the argument looks like a cast operator.
(integer) is an alias of (int). There are also (bool)/(boolean) and (float)/(double)/(real).
There is an (array) operator for converting to an array and (object) for converting to an object. This sounds sweet, but there is often a use case: you can use (array) to make a function parameter, which can be a single element or a list, treated the same. But this is unreliable, because if someone passes a single object, converting it to an array will actually produce an array containing the object's properties. (Converting to object performs the inversion operation.)
Functions such as include() are basically C’s #include: they transfer the source code of other files into your file. There is no module system, not even for PHP code.
There is no such thing as nested or locally scoped functions or classes. They are all global. include a file, its variables are imported into the current function scope (giving the file the ability to access your variables), but the functions and classes are stored in the global scope.
To append an array use $foo[]=$bar.
Echo is not a function.
empty($var) is so extreme that it does not behave as a function for anything other than variables, e.g.empty($var||$var2), which is a parsing error. Why is there such a thing on earth, and why does the parser need to know about empty?
There are also some redundant syntax blocks: if(…):…endif;, etc.
Error handling
A unique operator in PHP is @ (actually borrowed from DOS), which hides errors.
PHP error does not provide stack trace. You have to install a processor to generate them. (But not fatalerrors - see below.)
PHP parsing errors usually only throw the parsing status and nothing else, making debugging very bad.
PHP’s parser refers to e.g. :: internally as T_PAAMAYIM_NEKUDOTAYIM, and the << operator as T_SL. I say "internally", but as said above, the :: or << shown to the programmer appear in the wrong place.
Most error handling prints a line of error log to the server log, and no one sees it and keeps doing it.
E_STRICT looks like that, but it actually has little protection and no documentation showing what it actually does.
E_ALL contains all error categories—except E_STRICT.
It’s weird and inconsistent about what is allowed and what isn’t. I don't know how E_STRICT applies here, but these are correct:
Attempting to access a non-existent object property, such as $foo->x.(warning)
Use variables as function names, variable names, or class names. (silent)
An attempt was made to use an undefined constant. (notice)
An attempt was made to access a property of a non-object type. (notice)
Attempting to use a variable name that does not exist. (notice)
2<“foo”(hidden)
foreach(2as$foo);(warning)
But the following will not work:
Attempting to access non-existent class constants, such as $foo::x.(fatalerror)
Use string constants as function names, variable names, or class names. (parseerror)
Attempting to call a defined function. (fatalerror)
Leavingoffasemicolononthelaststatementinablockorfile.(parseerror)
Use list and other quasi-built-in macros as method names. (parseerror)
Use subscripts to access the return value of the function, such as: foo()[0]. (parseerror; fixed in 5.4)
There are several good examples of other weird parsing errors elsewhere in the list
The __toString method cannot throw an exception. If you try, PHP will...well, throw an exception. (It’s actually a fatalerror and can be passed, except...)
PHP errors and PHP exceptions are completely different species. They cannot interact.
PHP errors (internally, called trigger_error) cannot be caught by try/catch.
Similarly, exceptions cannot trigger errors through the error handler installed by set_error_handler.
As an alternative, there is a separate set_exception_handler that can handle uncaught exceptions, since wrapping the entry point of your program in a try block is not possible in the mod_pho module.
Fatal errors (e.g., newClassDoesntExist()) cannot be caught by anything. A large number of completely harmless operations can throw fatal errors, forcing you to terminate your program for some controversial reason. Shutdown functions still run, but they cannot obtain stack traces (they run on top), and they have difficulty telling whether the program ended by an error or by normal operation of the program.
There is no finally structure, which makes the packaging code (register processor, run code, unregister processor; monkeypatch, run test, unmonkeypatch) ugly and difficult to write. Although OO and exceptions heavily copy Java's patterns, this is intentional, because finally "in the context of PHP, it has to be out of place". Huh?
Function
Function calls seem to be quite expensive.
Some built-in functions interact with reference-returning functions in, well, a weird way.
As mentioned elsewhere, many things that look like functions, or look like they should be functions, are actually part of the language, and therefore do not work like normal functions.
Function parameters can have "type hints", which are basically just static types. You can't require a parameter to be an int or a string or an object or other "core" type, even though every built-in function uses this type, probably because int is not a thing in PHP. (See discussion of (int) above). You also cannot use special pseudo-type decorations used by a large number of built-in functions: mixed, number, or callback.
Therefore, below:
Function foo(string $s) {}
foo("hello world");
Error theerror:
PHPCatchablefatalerror: Argument1passedtofoo()mustbeaninstanceofstring, stringgiven, calledin…
You may notice that "type hints" don't actually exist; there is no string class in the program. If you try to dynamically test a type hint using ReflectionParameter::getClass(), you will get that the type does not exist, making it virtually impossible to obtain the type name.
Function return values cannot be inferred
Passing the parameters of the current function to another function (dispatch, not uncommon) is completed by call_user_func_array(‘other_function’, func_get_args()). But func_get_args throws a fatal error at runtime, complaining that it cannot be used as a function argument. Why is this a type error? (Fixed in PHP5.3)
Closures need to explicitly name each variable closed-over. Why doesn’t the parser work around that? (Okay, it’s because using avariableever, atall, creates itunlessexplicitlytoldotherwise.)
Closed-over variables are "passed" with the same semantics as other function parameters. In this case, arrays and strings, etc., will be passed to the closure by value. Unless using &.
Because closure variables automatically pass parameters and there is no nested scope, closures cannot point to private methods, whether defined in a class or not. (Maybe fixed in 5.4? Not sure.)
The function has no named parameters. Actually rejected by devs because it "causes code smell".
Functionargumentswithdefaultscanappearbeforefunctionargumentswithout,eventhoughthedocumentationpointsoutthatth
isisbothweirdanduseless.(Sowhyallowit?)
Extra parameters passed to the function will be ignored (except for built-in functions, which will throw an exception). Missing parameters are assumed to be null.
“Variable” functions require func_num_args, func_get_arg, and func_get_args. There is no syntax for such things.
OO
The functional part of PHP is designed to be similar to C, but the object-oriented (hoho) part is designed to be similar to Java. I don’t want to overemphasize how dissonant this is. I've yet to find a global function with capital letters, important built-in classes named in camelCase, and a Java-style property accessor like getFoo. This is a dynamic language, right? Perl, Python, and Ruby all have some concept of accessing "properties" through code; PHP just has clunky __get and the like. The type system is designed around the low-level Java language. Java and PHP are in the same era. Java intentionally makes more restrictions and copies Java. I am puzzled.
Classes are not objects. Metaprogramming has to point to them via string names, just like functions.
Built-in types are not objects, and (unlike Perl) cannot be made to look like objects.
Instanceof is an operator, although it was added very late, and most languages have specialized functions and syntax. Influenced by Java? Classes aren't first class? (I don't know if they are.)
But there is an is_a function. It has an optional parameter that specifies whether to allow the object to actually be a string-named class.
get_class is a function; there is no typeof operator. There is also is_subclass_of.
However, this doesn’t work for built-in types (again, int is not a thing). This way, you need is_int and so on.
An rvalue must be a variable or literal; it cannot be an expression. Otherwise it would result in... a parsing error.
Clone is an operator?!
OO design is a monster that mixes Perl and Java.
Object properties go through $obj->foo, but class properties go through $obj::foo. I haven't seen any other language do this, or see any use for it.
However, instance methods can still be called statically (Class::method). If called from other methods, it will be treated as a regular method call on the current $this. I think so.
new, private, public, protected, static, etc. Trying to win over Java developers? I know it's more of a personal taste thing, but I don't know why these things are necessary in a dynamic language - in C++, most of them are about assembly and compile time naming resolution.
Subclasses cannot override private methods. Public methods covered by subclasses are also not visible, and private methods of superclasses are called separately. There will be problems, such as when testing mocks objects.
Methods cannot be named, for example, "list" because list() is a special syntax (not a function) and the parser will be confused. The reason for this ambiguity is unknown, but classes work just fine. ($foo->list() is not a syntax error.)
If an exception is thrown when parsing the constructor parameters (e.g., newFoo(bar()) and bar() throws), the constructor will not be called, but the destructor will. (Fixed in PHP5.3)
Exceptions in __autoload and parsing functions will cause fatal errors.
There is no constructor or destructor. __construct is an initialization function, like Python's __init__. You cannot apply for memory and create objects by calling a class.
There is no default initialization function. When calling parent::__construct(), if the parent class does not define its own __construct method, a fatal error will occur.
OO brings an iterator interface, which is part of the language specification (such as...as...), but this interface actually has no built-in implementation (such as array). If you want an array iterator, you have to wrap it with ArrayIterator. There is no built-in way for iterators to work as first-class objects.
Classes can override how they convert to strings, but not how to convert to numbers or any other built-in type.
Strings, numbers, and arrays all have string conversion methods; the language relies heavily on this. Functions and classes are both strings. However, if __toString is not defined, trying to convert a built-in or custom object (or even a closure) into a string will cause errors, and even echo may fail.
Cannot overload equality or comparison operations.
Static variables in instance methods are global; their values are shared across multiple instances of the class.
Standard library
Perl "Something needs to be compiled". Python is "batteriesincluded". PHP is "the kitchen sink, it comes from Canada but all the faucets are branded C".
Summary
There is no type system. You can compile PHP, but you have to specify what to load via php.ini, options are either present (injecting their contents into the global namespace) or not by extension.
Because namespaces are a recent feature, the standard library is not disrupted at all. There are thousands of functions in the global namespace.
Some parts of the library are very inconsistent.
Underscore vs. no underline: strpos/str_rot13, php_uname/phpversion, base64_encode/urlencode, gettype/get_class
"to" pair 2: ascii2ebcdic, bin2hex, deg2rad, strtolower, strtotime
Object+verb versus verb+object: base64_decode, str_shuffle, var_dumpversuscreate_function, recode_string
Parameter order: array_filter($input, $callback)versusarray_map($callback, $input), strpos($haystack, $needle)versusarray_se
arch($needle, $haystack)
Prefix confusion: usleepvsmicrotime
Caseinsensitivefunctionsvaryonwheretheigoesinthename.
About half of the array functions start with array_. The rest are not.
Kitchen sink. Libraries include:
Bind ImageMagick, bind GraphicsMagick (a derivative of ImageMagick), a few functions can detect EXIF data (ImageMagick can already do this)
Function to parse bbcode, some very special tags, used by a few forum packages.
Too many XML packages. DOM(OO), DOMXML(not), libxml, SimpleXML, "XMLParser", XMLReader/XMLWriter, and a bunch of stuff I can't recognize have been omitted. Of course there are some differences, and you are free to figure them out.
Binded with two special credit card processors, SPPLUS and MCVE. What?
Three ways to access the MySQL database: mysql, mysqli, and some abstractions of PDO.
C Influence
It needs to have its own symbol. PHP is a high-level, dynamically typed language. And then a lot of the standard library parts are still just thin wrappers around CAPIS, along with the following:
“Out” parameters, although PHP can return an ad-hoc hash or return multiple parameters effortlessly.
At least a dozen functions are designed to get the last error in a certain subsystem (see below), even though PHP has had exception handling functionality for 8 years.
There is a mysql_real_escape_string, even though there is already a mysql_escape_string with the same parameters, simply because it is part of MySQLCAPI.
Global behaviors are non-global functions (such as MySQL). Using multiple MySQL connections requires explicitly passing the connection handle to each function call.
The wrapper is really, really, really thin. For example, calling dba_nextkey without calling dba_firstkey will cause a segfault.
There are a bunch of ctype_* functions (such as ctype_alnum) that map to C character functions with similar names, instead of, for example, isupper.
Genericism
If a function does two slightly different things, PHP creates two functions.
How do you reverse sort? In Perl, you can use {$b<=>$a}. In Python, you might use .sort(reverse=True). In PHP, there is a special function called rsort().
Those functions that look like Cerror: curl_error, json_last_error, openssl_error_string, imap_errors, mysql_error, xml_get_error_code, bzerror, da
te_get_last_errors, are there any others?
Sorting functions: array_multisort, arsort, asort, ksort, krsort, natsort, natcasesort, sort, rsort, uasort, uksort, usort
Text retrieval functions: ereg, eregi, mb_ereg, mb_eregi, preg_match, strstr, strchr, stristr, strrchr, strpos, stripos, strrpos, strripos, m
b_strpos, mb_strrpos, plusthevariationsthatdoreplacements
There are a large number of aliases: strstr/strchr, is_int/is_integer/is_long, is_float/is_double, pos/current, sizeof/count, chop/rtrim, implode/join, die/exit, trigger_error/user_error...
Scandir returns a list of files in the currently given directory. Instead of (potentially beneficially) returning in directory order, the function returns a sorted list of files. There is an optional parameter to return alphabetically in reverse order. These are obviously not enough for sorting.
str_split splits the string into equal-length chunks. chunk_split splits the string into equal-length chunks and then concatenates them with a separator.
Reading compressed files requires a separate set of functions, depending on the format. There are six sets of functions with different APIs, such as bzip2, LZF, phar, rar, zip, and gzip/zlib
Because calling a function with an argument array is so awkward (call_user_func_array), there are companions like printf/vprintf and sprintf/vsprintf. They do the same thing, but one takes multiple arguments and the other takes an array of arguments.
Text
Preg_replace with the /e(eval) flag will replace the matching part with the string to be replaced, and then eval it.
The design of strtok is obviously equivalent to a C function, which has been considered a bad idea for many reasons. PHP can easily return an array (which is awkward in C), and many hackstrtok(3) usages (modifying a string somewhere) cannot be used here.
Parse_str parses the query string, and there is no clue from the function name. Instead it will register_globals and dump the query string into a local scope variable unless you pass it an array to populate. (Of course, nothing is returned)
When encountering an empty delimiter, explode will refuse to split. Every other string splitting implementation that takes this approach is supposed to mean that the string should be split into characters; PHP has a split function, confusingly called str_split but described as "Convert a string into array".
Format date, there is strftime, just like CAPI handles local locale. Of course there is also date, which has a completely different syntax and is only used in English.
"gzgetss—Get the line pointer of the gz file and remove the HTML tag." Knowing the concept of this series of functions, let me die.
mbstring
It’s all about “multi-byte”, solving character set problems.
Still processing ordinary strings. There is a single global "default" character set. Some functions allow specifying a character set, but this depends on all parameters and return values.
The ereg_* functions are provided, but these have been deprecated. preg_* is lucky that, with some PCRE-specific tags, they understand UTF-8.
System and Reflection
There are a bunch of functions focusing on text and variables. Compression and extraction are just the tip of the iceberg.
There are several ways to make PHP dynamic, but at first glance there are no obvious differences or relative benefits. Class tools cannot modify custom classes; runtime tools replace it and can modify anything custom; Reflection* classes can reflect most things in the language; there are many unique functions for reporting functions and class properties. Are these subsystems independent, related, and redundant?
get_class($obj) returns the class name of the object. get_class() returns the name of the class in the called function. That aside, the same function does completely different things: get_class(null)... behaves like the latter. So when faced with a random variable, you can't trust it. Be surprised!
The stream_* classes allow the implementation of custom stream objects for use with fopen and other built-in file processing things. Due to several internal reasons, "notification" cannot be implemented.
Register_tick_function can accept closure objects. unregister_tick_function won't work; instead, it will throw an error complaining that the closure cannot be converted to a string.
php_uname tells you things related to the current operating system.
Fork and exec are not built-in. They come from the pcntl extension but are not included by default. popen does not provide pid files.
session_decode is used to read any PHP session string, but only works when there is an active session. It dumps the result into $_SESSION rather than returning its value.
Miscellaneous items
curl_multi_exec does not change curl_error when an error occurs, but it changes curl_error.
The parameters of mktime are in order: hour, minute, second, month, day, year
Data manipulation
The program is nothing but chewing and spitting out data. A large number of languages are designed around data manipulation, from awk to Prolog to C. If a language can't manipulate data, it can't do anything.
Numbers
Integers are signed 32-bit numbers on 32-bit platforms. Unlike its PHP contemporaries, there is no automatic bigint promotion. Therefore your math operations may result in different results depending on the CPU architecture. The only way you can select large integers is to use GMP or BC wrapper functions. (The developers may have already built a new, separate, 64-bit type. That would be crazy.)
PHP supports octal number syntax, starting with 0, so 012 is 10. However, 08 becomes 0.8 (or 9) and any following digits disappear. 01c is a syntax error.
PI is a function. Or there is a constant, M_PI.
There is no power operator, only the pow function.
Text
No Unicode support. Only ASCII work is reliable, really. There is an mbstring extension, mentioned above, but it's a bit of a hit.
This means that using the built-in string functions to process UTF-8 text is risky.
Similarly, outside of ASCII, there is no concept of case comparison. Although there are extended versions of case-sensitive functions, they do not consider é to be equal to É.
You cannot interpolate keys in variables. For example, "$foo['key']" is a syntax error. You also cannot unquoteit (which will generate a warning everywhere!), or use ${…}/{$…}
"${foo[0]}" is correct. "${foo[0][0]}" is a syntax error. Bad copy of Perl-like syntax (two fundamentally different languages)?
Array
Ugh, what a shame.
This guy plays the role of list data type, operates hash, sorts set, parses list, and occasionally makes some strange combinations. How does it perform? In what way does it use memory? Who knows? No, I have other options anyway.
=> is not an operator. It is a special structure that only exists in array(...) and foreach structures.
Negative indexing does not work, even though -1 is a valid key value like 0.
Although this is a language-level data structure, there is no short syntax; array(…) is the short syntax. (PHP5.4 brings "literals", [...].)
The => structure is based on Perl, which allows foo=>1 without quotes. In PHP, you'll get a warning if you do this; there's no way to create hash string keys without quotes.
Array handling functions can often be confusing or behave erratically because they have to operate on lists, hashes, or possibly a combination of the two. Consider array grouping, "computing different parts of the array".
$first = array("foo" => 123, "bar" => 456);
$second = array("foo" => 456, "bar" => 123);
echo var_dump(array_diff($first, $second));
What does this code do? If array_diff treats the parameters as hashes, they are obviously different; the same keys have different values. If viewed as a list, they are still different; the order of the values is different.
In fact array_diff considers them equal because it treats them as sets: only comparing the values, ignoring the order.
Similarly, array_rand also has strange behavior when randomly selecting keys, which is not helpful for most use cases where you need to pick something out of a list.
Although a lot of PHP code relies on the order of keys:
array("foo", "bar") != array("bar", "foo")
array("foo" => 1, "bar" => 2) == array("bar" => 2, "foo" => 1)
What happens if the two arrays are mixed? I leave it to the reader to figure it out. (I don’t know)
array_fill cannot create a 0-length array; instead it issues a warning and returns false.
All (many...) sorting functions operate in place and return nothing. If you want to make a new copy of a sorted array, no way; you have to copy the array yourself, then sort it, and then use the array again.
But array_reverse returns a new array.
A bunch of sorted stuff and some key-value pairs sounds like some powerful way to handle function arguments, but, no way.
Non-array
The standard library contains "fast hashing" and "specific strong type" hash structure OO implementation. However, digging into it, there are 4 categories, each handling a different combination of key-value pair types. It's not clear why the built-in array implementation doesn't optimize these extremely common cases, nor what its relative performance is.
There is an ArrayObject class (implementing 4 different interfaces) that wraps an array to make it look like an object. Custom classes can implement the same interface. But there are only a limited number of methods, and half of them don't look like the built-in array functions, and the built-in array functions don't know how to operate on ArrayObject or other array-like types.
Function
Functions are not data. Closures are actually objects, but ordinary functions are not. You can't even reference them by their bare name; var_dump(strstr) will warn and guess that you meant the string literal, "strstr". Trying to tell the difference between a string and a "function" reference, no way.
Create_function is basically a wrapper around eval. It creates the function with a normal name and installs it globally (so it will never be garbage collected - don't use it in a loop!). It actually knows nothing about the current context because it's not a closure. The name contains a NUL byte, so it will never conflict with a normal function (because PHP's parser will fail if there is a NUL anywhere in the file).
Declaringafunctionnamed__lambda_funcwillbreakcreate_function—theactualimplementationistoeval-createthefunctionnamed__lambda_func, theninternallyrenameittothebrokenname.If__lambda_funcalreadyexists, thefirstpa
rtwillthrowafatalerror.
Others
Use (++) for NULL to generate 1. Use (–) for NULL to generate NULL.
There is no generator.
Web Framework
Execution environment
A single shared file, php.ini, controls most of PHP's functionality and weaves in complex rules for what to overwrite and when. PHP software can be deployed on any machine, so some settings must be overridden to make the environment work properly, which in many programs will violate the use of mechanisms like php.ini.
PHP basically runs as CGI. Each time the page is clicked, PHP recompiles the entire environment before execution. Even the development environment of Python's toy framework is not like this.
This has led to the formation of the entire "PHP accelerator" market, which can accelerate PHP by just compiling it once, just like other languages. Zend, the company behind PHP, uses this as their business model.
For a long time, PHP errors were output to the client by default—to help the development environment, I guess. I don't think this is the truth, but I still see the occasional mysql error appearing at the top of the page.
Whitespace outside tags, even within libraries, is treated by PHP as text and parsed into the response (or results in a "headersalreadysent" error). A popular practice is to ignore the ?> closing tag.
Deployment
The deployment method is often cited as the most advanced part of PHP: just deploy the file directly. Yes, it's easier than Python or Rury or Perl which requires starting the whole process. But PHP leaves a lot to be desired.
I would love to run web applications as an application server and reverse proxy them. This has the lowest cost and many benefits: you can manage servers and applications separately, you can run multiple or a small number of application processes according to the number of machines, without the need for multiple web servers, and you can run them as different users Application, you can choose the web server, you can remove the application without disturbing the web server, you can deploy the application seamlessly, etc. Welding your application directly to a web server is ridiculous, and there's no good reason to do it.
Every PHP application uses php.ini. But there's only one php.ini file, and it's global; if you're on a shared server and need to modify it, or if you're running two applications that require different settings, you're out of luck; you'll have to apply to the organization All necessary settings are placed in the application, either using ini_set or in the Apache configuration file or in .htaccess settings. If you can do it. Probably wow, you have a lot of places to check to figure out how to get the value that has been set.
Similarly, there is no easy way to "isolate" a PHP application, as it relies on other parts of the system. Want to run two applications, want different library versions, or different PHP versions themselves? Start building another copy of Apache.
The "bunch of files" approach, besides making routing look like a sick donkey, also means you have to be careful with whitelisting or blacklisting to control what is accessible because of your URL hierarchy That is the level of your code tree. Configuration files and other "local modules" need to be protected by something like C to avoid direct loading. Files in version control systems (such as .svn) need to be protected. With mod_php, everything in the file system is a potential entry; with an application server, there is only one entry, and the call is controlled only by the URL.
You can’t seamlessly upgrade a bunch of files that run CGI-style, unless you want your application to crash and exhibit undefined behavior when users click on your site between upgrades.
Although configuring Apache to run PHP is "simple", there are still some pitfalls. The PHP documentation recommends using SetHandler to make the .php file run in PHP mode. AddHandler seems to run well, but in fact there will be problems.
When you use AddHandler, you are telling Apache to "execute it as php", which is one possible way to handle .php files. But! Apache does not think so about file extensions. It is designed to support files such as index.html.en. With Apache, a file can have any number of extensions at the same time.
Guess, you have a file upload form that stores some files in a public directory. To ensure that no one can upload PHP files, you just check that the files cannot have a .php extension. All the attack needs to do is upload a file named foo.php.txt; your upload tool won't see the problem, Apache will think it's PHP and it will happily execute it.
It’s not a matter of “use original filenames” or “no better validation”; the issue is that your web server needs to be configured to run any legacy code that makes PHP “easy to deploy”. This isn't a theoretical problem; I've found many real-world sites with similar problems.
Missing features
I think all of this is centered around building a web application. PHP looks very reasonable and is one of its selling points. It is the "language of the web" and it deserves them.
No module system. PHP is a template.
No XSS filter. htmlspecialchars is not an XSS filter.
No CSRF protection. You have to do it yourself.
There is no universal standard database API. Things like PDO have to wrap the API of each specific database and abstract different parts separately.
No routing system. Your site structure is your file system structure.
No authentication or authorization.
No development server.
No interactive debugging mode.
No consistent deployment mechanism; just "copy all files to the server".
Safety
Language boundaries
PHP's poor security mechanisms can be amplified because it takes data out of one language and dumps it into another. This is a bad note. "