Phpstorm Intellisense / Code completion for inherited properties - intellisense

I have a problem with Phpstorm's code completion for inherited properties. There is an example from my code below.
class ParentClass
{
public $repository;
}
/*
* #property Entity\SubClassRepository $repository
*/
class SubClass extends ParentClass
{
public function __construct()
{
$this->repository= $this->em->getRepository('Entity\Subclass');
}
public function ExampleFunction()
{
$this->repository-> !Here i need the code completion!
}
}
The getRepository function returns SubClassRepository for param = Entity\SubClass or returns OtherClassRepository for param = Entity\OtherClass. Btw there is no exact type that it returns. Thus; i need to say Phpstorm what type $repository object of parent class is.
I know that Phpstorm uses Phpdoc notation for code completion. Thus i tried to use #property notation and added the lines below to SubClass.
/*
* #property Entity\SubClassRepository $repository
*/
It doesn't work. Do you have any idea?
Thanks much.

The problem was about my missing * character in annotations as #LazyOne said in his comment. #property tag is working perfect now.
It should read:
/**
* #property Entity\SubClassRepository $repository
*/

Related

PHPDoc return type for trait function

I have functions like the following in my code that return the object (for chaining):
/**
* Set properties
*
* #param $name
* #param $value
*
* #return \Boka10\Page\MenuItemConfig
*/
public function __set($name, $value)
{
$this->$name = $value;
return $this;
}
I want to move this function into a trait because, well, basically it is reused all the time.
My problem is, that the return $this line makes problems in the documentation section. In my PHPDoc it says (in this example) #return \Boka10\Page\MenuItemConfig.
How do I create a "global" trait method whose return documentation contains the correct typecast? Is it possible to do that or should I just add the __set function to each class?
I am not sure if I can explain what problem I am having here ;) What exactly would be the content of the #return tag in a globally used trait if all of these objects return their own instance?
After some digging and "hacking" I checked out the tests in Psalm and found, that the following seems to be the best method to comment these cases:
/**
* #method string somefunction($name, $value)
* #property string $name
*/
class ImplementTrait {
use MagicTrait;
}
The properties and methods are documented on the implementing class.
Note: I am using Psalm to check the code quality and this is psalms accepted way:
Psalm Tests for __call annotations
Psalm tests for __get/__set annotations
I use the following approach to add auto-completion in PHPStorm when using classes that implement some interfaces.
I create an interface with a skeleton of all target Trait public methods and extend it.
Example:
Trait MySimpleTrait {
/**
* #inheritDoc
*/
public function someMethod($someArg){
return doSomethingWithSomeArg($someArg);
}
}
Interface MySimpleTraitInterface {
/**
*
* This method do some thing with <var>$someArg</>
*
* #param mixed $someArg
* #return mixed
*/
public function someMethod($someArg);
}
interface MySimpleServiceInterface extends MySimpleTraitInterface
{
}
class MySimpleService implements MySimpleServiceInterface
{
use MySimpleTrait;
}
PHPStorm showing autocomplete for method defined in Trait:
PHPStorm showing phpDoc for method defined in Trait:
Seems absurd in 2022, but I have a lot of projects with PHP 5.6 and the syntax is supposed to be compatible (i.e., no typehint in non-scalar args or return functions).

Bridge Class Functions in React Native

Say I have a class called ExampleClass.
Say I then write code like so:
#objc(ExampleClass)
class ExampleClass: NSObject {
#objc class func exampleFunc() -> Void {
}
}
With an Objective-C file header like so:
#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
#interface RCT_EXTERN_MODULE(ExampleClass, NSObject)
RCT_EXTERN_METHOD(exampleFunc)
#end
Which I then consume in my React Native app like so:
console.log('exampleClass', React.NativeModules.ExampleClass);
console.log('exampleFunc', React.NativeModules.ExampleClass.exampleFunc)
The first console log results in {exampleFunc: f}
The second results in undefined,
Calling the function: React.NativeModules.ExampleClass.exampleFunc() results in an app crash with:
Exception 'exampleFunc is not a recognized Objective-C method.' was thrown while invoking setupLogger on target ExampleClass with params (
While changing only the Swift so that it reads:
#objc(ExampleClass)
class ExampleClass: NSObject {
#obj func exampleFunc() -> Void {
}
}
results in calling the function (which, yes) does nothing at present.
How can I expose class level variables? I am trying to write functional Swift, and I am using class methods to simulate structs.
I believe the problem is that RCT_EXPORT_METHOD() only works on instance methods, not class methods, according to my own similar problem and some discussion here: https://github.com/facebook/react-native/issues/2311
My use case is trying to bridge a getInstance() method for a Swift singleton class. This is problematic because when you reference NativeModules.ExampleClass from javascript, which has been exported with RCT_EXTERN_MODULE(), RN calls init() on its own, which you don't want for a singleton (init() reference: https://samwize.com/2017/02/09/calling-a-view-controller-function-from-react-native/)
The best way I've found to accomplish this is pretty ugly. I have a dummy wrapper class that does nothing except call methods on the singleton, and this is the class I export to Objective C (and therefore to React Native). It's basically like this:
#objc(StupidWrapperClass)
class StupidWrapperClass : NSObject {
#objc(pseudoSingletonSomeMethod)
public func pseudoSingletonSomeMethod() {
let singleton = ActualClass.getInstance()
singleton.someMethod()
}
}
and then in the .m bridge file:
#interface RCT_EXTERN_MODULE(StupidWrapperClass, NSObject)
RCT_EXTERN_METHOD(pseudoSingletonSomeMethod)
#end
You could do something like this for a class method, too:
#objc(StupidWrapperClass)
class StupidWrapperClass : NSObject {
#objc(pseudoClassMethod)
public func pseudoClassMethod() {
ActualClass.theRealClassMethod()
}
}
I know I'm kinda late to the party but I recently faced the same problem and I fixed it using a different approach. Adding to the answer given above by #thejoelpatrol, a different approach would be to store the object's reference created by react native in some static variable that would be accessible by you. Then we can use the variable to access the object created by react-native anytime.
Whenever React Native tries to instantiate the class, it would come to the init. inside the init, we can save the reference to the object created by RN.
#objc public class MyClass {
#objc public static var shared: MyClass?
init() {
MyClass.shared = self
}
}
The .m bridge file is as follows:
#interface RCT_EXTERN_MODULE(MyClass)
RCT_EXTERN_METHOD(myClassMethod)
#end

Property 'sharedInstance' not found on object of type ClassA

I am creating a swift framework. In that one class is like this as shown below.
import Foundation
#objc public class classA: NSObject {
public override init (){
super.init();
}
/**
Singleton intance is returned.
*/
public class var sharedInstance: classA {
struct Static {
static let instance = popeye();
}
return Static.instance
}
}
Now when i add this framework into a Objective c project and try to access "sharedInstance" i get this error.
Property 'sharedInstance' not found on object of type ClassA.
Fix it Replace 'sharedInstance' with 'sharedInstance'
But even if i try use Fix it, this issue isnt solved.
NOTE: This issue doesn't happen when i integrate this framework with a swift project!!!
I AM STUCK.. :(
I tried to reproduce your problem. At first the syntax highlighter in Xcode flagged the same error in Objective-C that you mentioned, but the code actually was built and ran fine.
However, there is a cleaner way of doing this. In your code you are using a computed type property, which is evaluated every time you access it! You work around this by introducing the struct Static, where you essentially do what could be done in classA itself, like this:
/**
Singleton intance is returned.
*/
public static var sharedInstance: classA = popeye()
Here we used a stored type property, which is a recommended way to implement singletons, see here:
https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/AdoptingCocoaDesignPatterns.html
And here is some documentation on different kinds of properties:
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html
Finally i was able to fix this with a minor change !! :)
Swift framework code
#objc class SingletonTest: NSObject {
// swiftSharedInstance is not accessible from ObjC
class var swiftSharedInstance: SingletonTest {
struct Singleton {
static let instance = SingletonTest()
}
return Singleton.instance
}
// the sharedInstance class method can be reached from ObjC
class func sharedInstance() -> SingletonTest {
return SingletonTest.swiftSharedInstance
}
// Some testing
func testTheSingleton() -> String {
return "Hello World"
}
}
Objective C parent project code
SingletonTest *aTest = [SingletonTest sharedInstance];
NSLog(#"Singleton says: %#", [aTest testTheSingleton]);

How to declare a property as a function in Swift?

Here is my code:
import Cocoa
class VC1: NSViewController {
let aFunctionVar ()->Void
}
The compiler however tells me: "Class VC1 has no initializers"
According to the swift example in Apple Swift iBook, they did their examplle like so:
var mathFunction: (Int, Int) -> Int = addTwoInts
But in my case, I'm trying to create a property variable. It is not yet known what the variable will be, so i can't set it there. Any help?
Edit - I already know how to make variables optional and lazy when it comes to simple String/Array/Dictionary types etc. But this is a function type property variable. It is meant to hold a function of type ()->Void. Any help on how this can be done?
In objectiveC this can be done by making a block property like this:
#property (nonatomic, copy) void (^aFunctionVar)();
Declare projectLaunchData as an optional var:
import Cocoa
class VC1: NSViewController {
var projectLaunchData: (()->Void)?
}
Then you can assign a value later:
func test() {
print("this works")
}
let myVC = VC1()
// assign the function
myVC.projectLaunchData = test
// Call the function using optional chaining. This will safely do nothing
// if projectLaunchData is nil, and call the function if it has been assigned.
// If the function returns a value, it will then be optional because it was
// called with the optional chaining syntax.
myVC.projectLaunchData?()
If the value will be known after the object is setup, you can use a lazy variable:
class LazyTester {
lazy var someLazyString: String = {
return "So sleepy"
}()
}
var myLazyTester = LazyTester()
myLazyTester.someLazyString
The compiler is giving you that error because you are defining a mandatory stored variable, projectLaunchData, but not giving it a value. If you know the variables value at init time, you can set it at init time.

How is #private implemented?

In Objective-C, I'm curious how access controls for instance variables, like #private,#protected, etc. are implemented.
I had considered that separate structures were being generated in some way like this:
#interface Foo {
int bar;
#private
int baz;
#public
int qux;
}
=> something along the lines of
struct Class_Foo_Protected {
int bar;
};
struct Class_Foo_Private {
int baz;
};
struct Class_Foo_Public {
int qux;
};
But I really have no idea. Anyone know how this was really done?
Those modifiers don’t change anything about the memory layout of your class. The compiler itself remembers which ivar is public, protected or private and emits errors if you try to access them from somewhere inappropriate. This is all done before any code is generated and doesn’t affect the generated code.