I need $this to work inside static class! How to achieve that? Any workaround? I have analyzed return of Get-PSCallStack in class context and found nothing useful.
I need this for (a) logging and for (b) calling other static methods of same class without mentioning its name again and again.
Sample code (PowerShell v5):
class foo {
static [void]DoSomething() {
[foo]::DoAnything() #works
#$this.DoAnything #not working
$static_this = [foo]
$static_this::DoAnything() #works
}
static [void]DoAnything() {
echo "Done"
}
}
[foo]::DoSomething()
Static classes do not have this pointer. See MSDN
Static member functions, because they exist at the class level and not
as part of an object, do not have a this pointer. It is an error to
refer to this in a static method.
You must call method by class name.
Related
Im trying to load my model in my controller and tried this:
return Post::getAll();
got the error Non-static method Post::getAll() should not be called statically, assuming $this from incompatible context
The function in the model looks like this:
public function getAll()
{
return $posts = $this->all()->take(2)->get();
}
What's the correct way to load the model in a controller and then return it's contents?
You defined your method as non-static and you are trying to invoke it as static. That said...
1.if you want to invoke a static method, you should use the :: and define your method as static.
// Defining a static method in a Foo class.
public static function getAll() { /* code */ }
// Invoking that static method
Foo::getAll();
2.otherwise, if you want to invoke an instance method you should instance your class, use ->.
// Defining a non-static method in a Foo class.
public function getAll() { /* code */ }
// Invoking that non-static method.
$foo = new Foo();
$foo->getAll();
Note: In Laravel, almost all Eloquent methods return an instance of your model, allowing you to chain methods as shown below:
$foos = Foo::all()->take(10)->get();
In that code we are statically calling the all method via Facade. After that, all other methods are being called as instance methods.
Why not try adding Scope? Scope is a very good feature of Eloquent.
class User extends Eloquent {
public function scopePopular($query)
{
return $query->where('votes', '>', 100);
}
public function scopeWomen($query)
{
return $query->whereGender('W');
}
}
$users = User::popular()->women()->orderBy('created_at')->get();
Eloquent #scopes in Laravel Docs
TL;DR. You can get around this by expressing your queries as MyModel::query()->find(10); instead of MyModel::find(10);.
To the best of my knowledge, starting PhpStorm 2017.2 code inspection fails for methods such as MyModel::where(), MyModel::find(), etc (check this thread), and this could get quite annoying.
One (elegant) way to get around this is to explicitly call ::query() wherever it makes sense to. This will let you benefit from free auto-completion and a nice formatting/indentating for your queries.
Examples
BAD
Snippet where inspection complains about static method calls
// static call complaint
$myModel = MyModel::find(10);
// another poorly formatted query with code inspection complaints
$myFilteredModels = MyModel::where('is_foo', true)
->where('is_bar', false)
->get();
GOOD
Well formatted code with no complaints
// no complaint
$myModel = MyModel::query()->find(10);
// a nicely formatted and indented query with no complaints
$myFilteredModels = MyModel::query()
->where('is_foo', true)
->where('is_bar', false)
->get();
Just in case this helps someone, I was getting this error because I completely missed the stated fact that the scope prefix must not be used when calling a local scope. So if you defined a local scope in your model like this:
public function scopeRecentFirst($query)
{
return $query->orderBy('updated_at', 'desc');
}
You should call it like:
$CurrentUsers = \App\Models\Users::recentFirst()->get();
Note that the prefix scope is not present in the call.
Solution to the original question
You called a non-static method statically. To make a public function static in the model, would look like this:
public static function {
}
In General:
Post::get()
In this particular instance:
Post::take(2)->get()
One thing to be careful of, when defining relationships and scope, that I had an issue with that caused a 'non-static method should not be called statically' error is when they are named the same, for example:
public function category(){
return $this->belongsTo('App\Category');
}
public function scopeCategory(){
return $query->where('category', 1);
}
When I do the following, I get the non-static error:
Event::category()->get();
The issue, is that Laravel is using my relationship method called category, rather than my category scope (scopeCategory). This can be resolved by renaming the scope or the relationship. I chose to rename the relationship:
public function cat(){
return $this->belongsTo('App\Category', 'category_id');
}
Please observe that I defined the foreign key (category_id) because otherwise Laravel would have looked for cat_id instead, and it wouldn't have found it, as I had defined it as category_id in the database.
You can give like this
public static function getAll()
{
return $posts = $this->all()->take(2)->get();
}
And when you call statically inside your controller function also..
I've literally just arrived at the answer in my case.
I'm creating a system that has implemented a create method, so I was getting this actual error because I was accessing the overridden version not the one from Eloquent.
Hope that help?
Check if you do not have declared the method getAll() in the model. That causes the controller to think that you are calling a non-static method.
For use the syntax like return Post::getAll(); you should have a magic function __callStatic in your class where handle all static calls:
public static function __callStatic($method, $parameters)
{
return (new static)->$method(...$parameters);
}
Is there any way for a static property in a Powershell class to contain a generic dictionary? Without the initialisation syntax that exists in C#, I haven't found a way to do it.
enum Environment
{
Production
QA
Dev
}
class Config
{
# How to get this populated?
static [System.Collections.Generic.Dictionary[Environment, hashtable]] $EnvData
}
Potential workarounds:
Add-Type and a C# class
A GetEnvData() method
Is there a better way I haven't thought of?
Just like in C#, you can use the static constructor (which is what initializers are syntactic sugar for, anyway):
class Config
{
static [System.Collections.Generic.Dictionary[Environment, hashtable]] $EnvData
static Config() {
$d = New-Object ([System.Collections.Generic.Dictionary[Environment, hashtable]])
$d["Production"] = #{Setting="Foo"}
[Config]::EnvData = $d
}
}
The use of a local is not strictly required, but I sleep better knowing the initialization is atomic.
You can also use an initializer ($EnvData = ...) but that's a little tricky in this case, since creating a generic Dictionary in one statement is, well, awkward, and the class syntax doesn't like it if you get complicated (pipes, nested function calls). You could still, if you so wanted, split off initialization into a separate hidden static function and call that for initialization (... $EnvData = [Config]::initialEnvData()), which may be more readable than one big constructor if you've got many conceptually independent properties.
I want to use a func delegate in my static PowerShell 5.0 class:
I had issues to find a way to assign other static class methods for my delegate.
This code is working but not very convinient.
Is there a better way to use a delegate here ?
And I need to instanciate my static! class, only to get the type.
I tried the outcommented line, how you would do it with .NET types, but it's not working for my own class.
How can I get the type of my static class here more elegant ?
And, BTW, GetMethod() did not accecpt the BindingFlags parameter, why ?
class Demo
{
hidden static [object] Method_1([string] $myString)
{
Write-Host "Method_1: $myString"
return "something"
}
hidden static [object] Method_2([string] $myString)
{
Write-Host "Method_2: $myString"
return $null
}
hidden static [object] TheWrapper([string]$wrappedMethod, [string] $parameter)
{
# do a lot of other stuff here...
#return [System.Type]::GetType("Demo").GetMethod($wrappedMethod).CreateDelegate([Func``2[string, object]]).Invoke($parameter)
return [Demo]::new().GetType().GetMethod($wrappedMethod).CreateDelegate([Func``2[string, object]]).Invoke($parameter)
}
static DoWork()
{
Write-Host ([Demo]::TheWrapper('Method_1', 'MyMessage'))
[Demo]::TheWrapper('Method_2', 'c:\my_file.txt')
}
}
[Demo]::DoWork()
You don't need to create an instance of [demo] since [demo] is the actual type of the class. Also, you can write the delegate type more simply as [Func[string,object]]. This simplifies the body of TheWrapper method to
return [Demo].GetMethod($wrappedMethod).CreateDelegate([Func[string, object]]).Invoke($parameter)
but a much simpler way to do this in PowerShell is to get the method by passing its name to the '.' operator then invoking the result:
return [demo]::$wrappedMethod.Invoke($parameter)
In PowerShell, the right-hand side of the '.' operator doesn't need to be a constant. You can use an expression that results in the name of the method (or property) to retrieve.
Looking at the addValues method below, this is not callable if I don't include the 'static' keyword. Why is this so?
namespace TryingMethods
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(addValues(3, 4));
}
public static int addValues(int left, int right)
{
return left + right;
}
}
}
It's because static method can only have acces to static variables and other static methods. Normally, you cannot call addValues(int left, int right) inside main() method which is static. Only way around is to have an instance of a class containing addValues() method.
When you do not say static , it means that the method is a 'property' of the object, which is an instantiation of this particular class. When you do not say static, it means that the method is not a property of the object, and thus, can be called without referring to the object.
For example, you could have a Person class, and there is a static method "Print hello" and there is a non-static method "Give me name". Printing hello is not relevant to the particular person, so it is static. "Give me name" is relevant to the particular person, so you need to call this method differently.
Person myMan = new Person();
myMan.giveMeName();
printHello();
You don't need to instanciate the class in order to call static methods.
Program.addValues(1,2)
static methods can't get/set class members
It's because you have your Main function declared as static, so the methods that you call in it need to be too. If you remove static from both you wouldn't get the error.
I have this Haxe class that is growing quite large. It consists mostly of static methods & properties. (It's a module set to compile as JS target).
I would like to separate some of the complex static functions into another class.
Is there any way to mark it with a metatag / indicate the other class is an "extension" to the original class?
Something like #:native("OriginalClass") class OtherClass {...}
The goal is to avoid having to write the full variable access (ex: OriginalClass.LOG_QUEUE vs. LOG_QUEUE) or clutter the imports with each OriginalClass's static methods / properties used at the top of the OtherClass. Basically, something to make it aware that it "is" using the same members as the OriginalClass (whenever an 'undefined' one is found, at compile-time).
Example:
If OriginalClass has static var LOG_QUEUE:Array<String>; then OtherClass would be aware that any usage of LOG_QUEUE compiles to this JS code OriginalClass.LOG_QUEUE
Alright, got a solution after discussing with Dima Granetchi from the Haxe experts group on Slack.
Now, although this will still generate the OtherClass that makes use of the OriginalClass's static members, you can cut down on the quantity of import statements for most (if not all) of the module/class's static members by using the wildcard * symbol, like in this example:
// OriginalClass.hx
package somePackage;
class OriginalClass {
public static var LOG_QUEUE:Array<String>;
public static function main() {
LOG_QUEUE = [];
OtherClass.doSomething();
}
public static function doSomethingOriginal() {
LOG_QUEUE.push("World!");
}
}
// OtherClass.hx
import somePackage.OriginalClass.*; // <-- Demonstrating the WILDCARD (*) symbol
class OtherClass {
public static function doSomething() {
LOG_QUEUE.push("Hello"); //Resolved to OriginalClass.LOG_QUEUE
doSomethingOriginal(); //Resolved to OriginalClass.doSomethingOriginal()
}
}
Although this is a minimal example, it becomes more useful when you have a few different dozen static members used in your OtherClass.
Note
TypeDefs defined in the OriginalClass used inside the OtherClass doesn't seem to get recognized/resolved (may be due to missing public accessor, but I was unable to set it on my typedefs). You can always import those specific TypeDefs with individual import statements, like so:
//Somewhere at the top of OtherClass.hx...
import somePackage.OriginalClass.MyTypeDef;