I have some method and a closure inside it. Exception can be thrown in this closure. This exception is declared in methods PHPDoc, but PhpStorm says that this exception is never thrown.
Do anyone know how to make PhpStorm see it? Declaring another PHPDoc before closure does not help.
Code looks like this:
/**
* #throws IAmInvisibleException - Sorry, but I don't know you
*/
private function some_nice_method(){
$some_var = (function(){
if($something_wrong)
throw new IAmInvisibleException();
})();
}
Related
I have a complex PHP project that contains two definitions for a function foo. One of those is in a vendor library, and I never use it, the other one I use a lot. The implementation in the vendor library throws an Exception, the correct implementation does not. Now anytime I write a function that calls foo(), PhpStorm's code inspections say I should declare a #throws \Execption in the caller's PhpDoc. I'd like to suppress that warning in this case, and maybe tell PhpStorm that I will never use the function in the vendor library.
I've experimented with Scopes, but couldn't make that work - I can prevent PhpStorm from reporting warnings in the vendor files, but not from analyzing them for symbols used in my own code.
Add /** #noinspection PhpDocMissingThrowsInspection */
or /** #noinspection ALL */ (for disable all inspections) at the top of method foo()
This is the stack trace I get:
[Fault] exception, information=Error: Directory id 3 already in use
at cantrips.assets.index::AssetIndex/dirIdChanged()[/home/luismasuelli/Proyectos/flash-assets-index-ritual/assets-index-loader/src/cantrips/assets/index/AssetIndex.as:72]
at flash.events::EventDispatcher/dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at cantrips.assets.index::AssetDirectory/set id()[/home/luismasuelli/Proyectos/flash-assets-index-ritual/assets-index-loader/src/cantrips/assets/index/AssetDirectory.as:68]
at Main/updateSelectedDirectory()[/home/luismasuelli/Proyectos/flash-assets-index-ritual/assets-index-editor/src/Main.mxml:192]
at Main/__dirUpdateCurrent_click()[/home/luismasuelli/Proyectos/flash-assets-index-ritual/assets-index-editor/src/Main.mxml:401]
This is the implementation of Main/updateSelectedDirectory():
private function updateSelectedDirectory():void {
try {
var newId:uint = uint(dirId.text);
var newName:String = StringUtil.trim(dirName.text);
var selectedDirectory:AssetDirectory = assetBrowserTree.selectedItem as AssetDirectory;
if (selectedDirectory) {
selectedDirectory.id = newId;
selectedDirectory.name = newName;
assetBrowserTree.expandItem(selectedDirectory.parent, false);
assetBrowserTree.expandItem(selectedDirectory.parent, true);
}
} catch (error:Error) {
Alert.show(error.message, "Cannot update");
}
}
Why is not the exception being caught by try {} catch(error:Error) {}?.
The exception is an exception created by me, with a well-understood scenario where it is triggered (I created the exception and designed those scenarios and I am testing them; exception is triggered as I expect). I also tried using the exact name of the exception (AssetIndexError) in the catch block, and no confusion or ambiguous name exists (this means: there's no another AssetIndexError class declared elsewhere I could be importing instead of this).
Explanation:
cantrips.assets.index is code I have control over.
Main/* is the main window. I also have control over that code.
Screenshot:
If you look at your stack, you'll see the error is not being thrown in the code shown (which is near the bottom of the stack), but here:
dirIdChanged at AssetIndex.as:72
Further down in the stack you'll see the following:
at flash.events::EventDispatcher/dispatchEvent()
This means that stack was asynchronous in between AssetDirectory.set id() and
AssetIndex.dirIdChanged()
When you add an event handler, all code in the current block will usually run prior to the event handler code (as they are not in the same thread).
So in this case, all your code in the try/catch will have run before the event handler's code - which is why the error is not being caught.
Any time you are handling an event, you will need to have another try/catch, or use an asynchronous error handling technique.
This is a complement the OP made to the accepted answer.
The main reason of this trouble is that I did not understand how the event flow is done.
The event flow is asynchronous, and I thought as it being synchronous. If the event flow was synchronous, it is not hard to think that what I intended was right: The exception could be thrown in the same execution stack and everything would be fine (i.e. a method calls another method, such method calls a third method, blah blah blah exception and explosion).
When the event flow is asynchronous as ActionScript flow is, the exception will be triggered in another execution stack, but somehow the information provided is misleading as it should as if the execution stack was the same.
The solution I implemented: A dumb object (i.e. a dumb new class) which acted like EventDispatcher but being synchronous: .dispatch() would not post an event execution to the event flow, but instead execute by itself the registered event handlers, as a loop over the handlers, and calling each handler by hand, without the possibility of having stuff like event.target populated in the handlers.
Althought this design could be seen as bad from many points of view I would agree with, in this case it fit my needs of handlers throwing exceptions and code executed synchronously.
My main application swf file is being loaded by a simple loader swf application that is useful to break cache. In both applications I would like to have access to a singleton. I will provide you with an example to reproduce the bug. So here's our singleton:
package {
public class SingletonTest {
public static const instance:SingletonTest = new SingletonTest();
public function SingletonTest() { /* Nothing here. */ }
public function test():void {
trace("SingletonTest!");
}
}
}
In constructors of both loader and main classes I call:
SingletonTest.instance.test();
That is made in order to be sure that my singleton class code will be included in both applications. I won't provide you with loader code but it's very simple. It creates Loader instance, it creates LoaderContext supplying it with both current ApplicationDomain and SecurityDomain, etc...
But when I launch my loader application I get following error:
Main Thread (Suspended: TypeError: Error #1034: Type Coercion failed:
cannot convert SingletonTest#47a3091 to SingletonTest.)
SingletonTest$cinit
I get this error right after main application was loaded with loader. Event.COMPLETE is not dispatched yet so no handlers involved. I spent a lot of time trying to find something about application or security domains but it seems like it's not the issue because what I found next is really strange. If instead:
public static const instance:SingletonTest = new SingletonTest();
I will write:
private static var _instance:SingletonTest;
public static function get instance():SingletonTest {
if (_instance == null) _instance = new SingletonTest();
return _instance;
}
Then there will be no such error and everything will be fine. Obviously flash player is performing some unexpected behavior here. There's very few information on this issue out there. Most of people get this error because of missing loader context but as I said before here it's not the case. Some discussions on this are even left without any answers which is strange to me because I find this to be quite a common problem to be encountered when using small applcation loader.
Spent almost 12 hours trying to solve the problem. At last found the solution. In order to avoid runtime error which I provided above you need to compile your singleton class into swc-library. That's it.
In my case that singleton was providing global access to logging and only option was to switch from singleton pattern to static class. But I didn't want it very much because I really like this one-line singleton instantiation: "public static cosnt instance:MyClass = new MyClass();".
Trying to implement the new FP 10.1 Global error handler into my projects but no matter what I do any uncaught error will still show up the Exception window (both in debug and release versions of the SWF). All I want to do is to prevent these popups but instead send a message to my logger. Here's my code ...
EDIT: I simplified the code now. Could somebody do me a favor and test the following class and see if it's works for him? Because it's doesn't for me! ...
package
{
import flash.display.Sprite;
import flash.events.UncaughtErrorEvent;
public class GlobalErrorHandlerTest extends Sprite
{
public function GlobalErrorHandlerTest()
{
stage.loaderInfo.uncaughtErrorEvents.addEventListener(UncaughtErrorEvent.UNCAUGHT_ERROR, onUncaughtError);
throw new Error();
}
private function onUncaughtError(e:UncaughtErrorEvent):void
{
var message:String;
if (e.error["message"])
{
message = e.error["message"];
}
else if (e.error["text"])
{
message = e.error["text"];
}
else
{
message = e.error["toString"]();
}
trace("Uncaught Error: " + e.text);
}
}
}
I had the same issue as above - I was referencing stage.loadInfo, believing that as that references the stage, it would capture all uncaught errors. However, that doesn't work, you have to actually follow grapefukt's suggestion verbatim: On the actual base display object, place the code
loaderInfo.uncaughtErrorEvents.add...
When you try to place onto stage.loaderInfo or frame.loaderInfo, it has no effect.
In my case, I had to place it in the class that extended the base display object. Very Odd.
The docs say that:
The UncaughtErrorEvents object that dispatches the event is associated with either a LoaderInfo object or a Loader object.
Thus you must listen to the loaderInfo's uncaughtErrorEvents property of your topmost display object:
loaderInfo.uncaughtErrorEvents.addEventListener(UncaughtErrorEvent.UNCAUGHT_ERROR, uncaughtErrorHandler);
UPDATE: I think I may know why you think this isn't working. I made the mistake of testing inside the debugger. When the debugger stopped on the runtime errors I assumed that this proved my uncaughtErrorHandler function was not working. In fact, this was in error. It's just a quirk of the debugger. The debugger will still stop as if it is an unhandled error or exception, but if you press Run again you'll see it DOES execute the error handling code. See my thread Flex 4.0/4.5 global error handling for more info.
Original response:
I am looking for this same info. None of the examples in the API doc nor various blogs on the subject work for me. I've tried just loaderInfo, stage.loaderInfo, systemManager.loaderInfo... It makes no difference. I even tried all of them in a single test case! The addEventListener are being set but the uncaught errors are not firing the uncaughtErrorHandler. Argh. I have wasted far too much time on this! I've reduced it to a very simple program much like above except with all the code in the main mxml file.
How about this: can someone post a Global Error Handling example that DOES work? I'm using Flex SDK 4.1 (I've also tried with 4.5), targeting FP 10.1 (or 10.2 for 4.5), in a mx:Application-based mxml Flex project.
My thread: Flex 4.0/4.5 global error handling
You must set up the listener not to a specific view, but to the main stage object, as it's at the top of the display list (thus picking up any exception of any of its children).
I have an MFC application compiled with /clr and I'm trying to implement a final handler for otherwise un-caught managed exceptions. For native exceptions, overriding CWinApp::ProcessWndProcException works.
The two events suggested in Jeff's CodeProject article,Application.ThreadException and AppDomain.CurrentDomain.UnhandledException, are not raised.
Can anyone suggest a way to provide a final managed exception handler for a mixed executable?
Update:
It appears that these exception handlers are only triggered downstream of Application.Run or similar (there's a worker thread flavor, can't remember the name.) If you want to truly globally catch a managed exception you do need to install an SEH filter. You're not going to get a System.Exception and if you want a callstack you're going to have to roll your own walker.
In an MSDN forum question on this topic it was suggested to override a sufficiently low-level point of the main MFC thread in a try ... catch (Exception^). For instance, CWinApp::Run. This may be a good solution but I haven't looked at any perf or stability implications. You'll get a chance to log with a call stack before you bail and you can avoid the default windows unahndled exception behavior.
Taking a look around the internets, you'll find that you need to install a filter to get the unmanaged exceptions passing the filters on their way to your AppDomain. From CLR and Unhandled Exception Filters:
The CLR relies on the SEH unhandled exception filter mechanism to catch unhandled exceptions.
Using those two exception handlers should work.
Why "should?"
The events are not raised using the below:
extern "C" void wWinMainCRTStartup();
// managed entry point
[System::STAThread]
int managedEntry( void )
{
FinalExceptionHandler^ handler = gcnew FinalExceptionHandler();
Application::ThreadException += gcnew System::Threading::ThreadExceptionEventHandler(
handler,
&FinalExceptionHandler::OnThreadException);
AppDomain::CurrentDomain->UnhandledException += gcnew UnhandledExceptionEventHandler(
handler,
&FinalExceptionHandler::OnAppDomainException);
wWinMainCRTStartup();
return 0;
}
// final thread exception handler implementation
void FinalExceptionHandler::OnThreadException( Object^ /* sender */, System::Threading::ThreadExceptionEventArgs^ t )
{
LogWrapper::log->Error( "Unhandled managed thread exception.", t->Exception );
}
// final appdomain exception handler implementation
void FinalExceptionHandler::OnAppDomainException(System::Object ^, UnhandledExceptionEventArgs ^args)
{
LogWrapper::log->Error( "Unhandled managed appdomain exception.", (Exception^)(args->ExceptionObject) );
}
BOOL CMyApp::InitInstance()
{
throw gcnew Exception("test unhandled");
return TRUE;
}
Using those two exception handlers should work. Are you sure you've added them in a place where they're going to be called and properly set (ie, in your application's managed entry point -- you did put one in, right?)