Shoud I use trigger_error in PHP8 - error-handling

I am revising a PHP project that is necessary because of a massive redesign in the database.
Therefore, the project should use the latest PHP version, which at the moment of writing is version 8.
I am also using an OOP approach with namespace, so the project can benefit from features like autoloading in the future.
In the new classes I wrote, I need to throw errors.
But in PHP 8, there are so many ways to do this.
I could use trigger_error or exceptions or the error class and its specific variants like value error.
Now I am unsure which to choose.
Currently I have a mixture of exceptions and trigger_error in the code.
I have a custom handler defined for both exception and "old" errors, which writes the errors to a log file so I can fix them (if possible).
So what should I use to write a future-proof code?
Unfortunately I couldn't find anything in the PHP docs about this.
Also my web research didn't bring any useful result unfortunately.
Is there a best approach rule?

I'm not a PHP expert.
However my little observation is that latest PHP versions tend to be more OOP. PHP now supports many OOP features you will find in any other fully OOP languages like C# or Java. We can see that many PHP functions now throw exceptions, and with the introduction of Exception and Error in PHP 7 and ValueError in PHP 8 you are likely to encounter and have to deal with exceptions than the infamous false and null.
A very small list of PHP features that now throw excptions (with versions next to them):
Constructors of internal classes will now always throw an exception (PHP 7)
Calling a function with less arguments than mandatory declared ones throws exception (PHP 7.1)
1 + "a" throws TypeError (PHP 8)
explode throws ValueError when separator parameter is given an empty
string (PHP 8)
mb_ord throws ValueError when $string argument is given an empty string (PHP 8)
MySQLi the default error handling mode has been changed from "silent" to
"exceptions" (PHP 8.1)
And many more will throw an instance of Error or exception instead of resulting in a fatal error.
Conclusion
Throw exceptions instead of using trigger_error.

Related

Razor view errors while Migrating from core 2.2 to 3.1

After doing the general upgrade steps for the migration. My razor had 100's of errors suddenly after removing Microsoft.AspNetCore.All. These error were not consistent, these were general compiler errors.
Some combination of
IDE1007 C# The name does not exist in the current context.
CS0111 C# Type already defines a member called with the same parameter types
CS0538 C# in explicit interface declaration is not an interface
CS0116 C# A namespace cannot directly contain members such as fields
or methods
CS8107 C# Feature is not available in C# 7.0. Please use
language version 9.0 or greater.
Just all over the place stuff, and this was all working perfectly in 2.2
I was able to fix this. What I found was that we had few places in the code where we were using # inside a razor block, this used to work fine but breaks in core 3.1. I am assuming that the process of generating the classes by Razor SDK was failing because I was also getting errors in index.g.cshtml.cs.
We probably had this issue in 5 files at most but we were getting 500+ build errors. Very frustrating, so adding this answer because I was not able to find any similar answer anywhere.
Example of bad code, notice the extra # inside {}.
#{ var replacements = new string[] { #Model.TotalItemsInCart.ToString() };}

SWI-prolog pure logic programming modules fail

I am working in SWI-Prolog.
We have been asked to do some 'pure logic' implementations, and to do so, some modules have to be added to the code (in order to control the execution of the code). Let us take one of them:
:- module(_,_,[]).
My code works fine without it, but when I add it (at the beginning of it), it fails with the message: Arguments are not sufficiently instantiated.
I have also tried adding :- module(_,_,[]). in an empty file and still fails with the same error; so it is not a problem of my code, but a problem of the module.
I have searched for the error, but I only find it related to a different problem: usually using some variable before declaring it, like in (Prolog - Arguments are not sufficiently instantiated).

Find potential problems through log files

If there is a problem in the source code, usually a programmer goes through the log manually and tries to identify the problem in the source code.
But is it possible to automate this process? Can we automate the process that would give the potential lines in the source code that was responsible for generating the fault.
So, for example:
If there is some problem in the log file. Then this automation tool should say that this problem has occurred due to line 30,31,32,35,38 in source code ABC
Thanks!!
It depends on the language you are using.
In Java (and probably other JVM languages) this feature is built-in: Every exception that is thrown has a reference to the stack trace, including class, method and line number of every method involved. All you need to do is something like
exception.printStackTrace();
In C and C++, you can use preprocessor macros like __FUNCTION__ or __LINE__ when throwing an exception or writing a log message, for example:
throw "Error in " + __FUNCTION__ + ", line " + std::to_string(__LINE__);
The macros will be replaced by the current function and the current line.
If you are looking for a method that works with any language and any type of logging, there is no good solution. You could run a tool like grep over all source files, that will try to find matches. However this will only work if the log messages appear as string literals in source code at the position where the message is written. This is unlikely because the messages are likely to contain variable values or constants defined somewhere else.
Assuming we are not talking about (unit) testing, because this is what they do - show you where is the problem exactly.
Then this automation tool should say that this problem has occurred due to line 30,31,32,35,38 in source code ABC
In my team we had similar discussion and what we've come with is a Top5 most likely issues document (PlayBook). After reading logs every time on failure, we've noticed that in most of the times there is a requiring pattern. So 8 out of 10 cases the issues were following one of those patterns. So it is possible to trace the latest changes (with the help from Git). If your changes are small and frequent - this approach works quite well.

In what languages or environments will a program NOT be in a well-defined (or stable) state after an exception is thrown?

I'm learning Objective-C from the book "Programming in Objective-C" and find myself comparing it to Java. They are obviously very different languages, but the similarities are striking. Near the end of chapter 9 the author issues the following statement;
It is strongly recommended that if you catch an exception you only do
so with the intention of cleaning up and terminating your application.
Why? Because Apple does not guarantee that your application will be in
a well-defined state for continuing program execution once an
exception is thrown.
This is very different from Java, where depending on the exception itself, you can continue program execution (eg: if you try opening a configuration file, but get an exception of "File not found", you can select some default values and continue without issues). I believe the same is true for C#/.NET. Probably for python too, but I'm no authority.
I'm guessing that since Objective-C isn't running on some framework/runtime-environment, Apple can't make any guarantees about program state after an exception is thrown. But that still feels weird since, it defeats one of the biggest selling points of OOP (to isolating issues from propagating unchecked) i.e. if your code catches an exception (barring the object that threw the exception), the rest of your program should be fine.
Without knowing how Apple's Objective-C works underneath, I don't think it will be easy to puzzle out. This got me wondering;
From an academic perspective (and simple curiosity) - In what modern OOP languages+environments will an application be in a potentially unstable state after an exception is thrown?

internal error markers

Theoretically, the end user should never see internal errors. But in practice, theory and practice differ. So the question is what to show the end user. Now, for the totally non-technical user, you want to show as little as possible ("click here to submit a bug report" kind of things), but for more advanced users, they will want to know if there is a work around, if it's been known for a while, etc. So you want to include some sort of info about what's wrong as well.
The classic way to do this is either an assert with a filename:line-number or a stack trace with the same. Now this is good for the developer because it points him right at the problem; however it has some significant downsides for the user, particularly that it's very cryptic (e.g. unfriendly) and code changes change the error message (Googling for the error only works for this version).
I have a program that I'm planning on writing where I want to address these issues. What I want is a way to attach a unique identity to every assert in such a way that editing the code around the assert won't alter it. (For example, if I cut/paste it to another file, I want the same information to be displayed) Any ideas?
One tack I'm thinking of is to have an enumeration for the errors, but how to make sure that they are never used in more than one place?
(Note: For this question, I'm only looking at errors that are caused by coding errors. Not things that could legitimately happen like bad input. OTOH those errors may be of some interest to the community at large.)
(Note 2: The program in question would be a command line app running on the user's system. But again, that's just my situation.)
(Note 3: the target language is D and I'm very willing to dive into meta-programming. Answers for other languages more than welcome!)
(note 4: I explicitly want to NOT use actual code locations but rather some kind of symbolic names for the errors. This is because if code is altered in practically any way, code locations change.)
Interesting question. A solution I have used several times is this: If it's a fatal error (non-fatal errors should give the user a chance to correct the input, for example), we generate a file with a lot of relevant information: The request variables, headers, internal configuration information and a full backtrace for later debugging. We store this in a file with a generated unique filename (and with the time as a prefix).
For the user, we present a page which explains that an unrecoverable error has occurred, and ask that they include the filename as a reference if they would like to report the bug. A lot easier to debug with all this information from the context of the offending request.
In PHP the debug_backtrace() function is very useful for this. I'm sure there's an equivalent for your platform.
Also remember to send relevant http headers: Probably: HTTP/1.1 500 Internal Server Error
Given a sensible format of the error report file, it's also possible to analyze the errors that users have not reported.
Write a script to grep your entire source tree for uses of these error codes, and then complain if there are duplicates. Run that script as part of your unit tests.
I know nothing about your target language, but this is an interesting question that I have given some thought to and I wanted to add my two cents.
My feeling has always been that messages for hard errors and internal errors should be as useful as possible for the developer to identify the problem & fix it quickly. Most users won't even look at this error message, but the highly sophisticated end users (tech support people perhaps) will often get a pretty good idea what the problem is and even come up with novel workarounds by looking at highly detailed error messages. The key is to make those error messages detailed without being cryptic, and this is more an art than a science.
An example from a Windows program that uses an out-of-proc COM server. If the main program tries to instantiate an object from the COM server and fails with the error message:
"WARNING: Unable to Instantiate
UtilityObject: Error 'Class Not
Registered' in 'CoCreateInstance'"
99% of users will see this and think it is written in Greek. A tech support person may quickly realize that they need ro re-register the COM server. And the developer will know exactly what went wrong.
In order to associate some contextual information with the assertion, in my C++ code I will often use a simple string with the name of the method, or something else that makes it clear where the error occured (I apologize for answering in a language you didn't ask about):
int someFunction()
{
static const std::string loc = "someFunction";
: :
if( somethingWentWrong )
{
WarningMessage(loc.c_str(), "Unable to Instantiate UtilityObject: Error 'Class Not
Registered' in 'CoCreateInstance);
}
}
...which generates:
WARNING [someFunction] : Unable to
Instantiate UtilityObject: Error
'Class Not Registered' in
'CoCreateInstance