azjezz / psl Goto Github PK
View Code? Open in Web Editor NEW📚 PHP Standard Library - a modern, consistent, centralized, well-typed, non-blocking set of APIs for PHP programmers
License: MIT License
📚 PHP Standard Library - a modern, consistent, centralized, well-typed, non-blocking set of APIs for PHP programmers
License: MIT License
Psl\Str\encoding
to Psl\Str\detect_encoding
Psl\Str\convert_encoding(string $string, string $from, string $to): string
( see: https://www.php.net/manual/en/function.mb-convert-encoding.php )Psl\Str\is_utf8(string $string): bool
Hello,
Today I landed on this repository. It looks very similar with something I am creating:
https://github.com/veewee/happy-helpers
Feel free to check it out.
There are:
Besides what is in there, I also put some thought in stuff like file resources, but nothing concrete.
My intention of that package was mostly learning, but I am using it in some of my private projects and would love to introduce a far more advanced version in customer projects. I was not planning of putting a lot of extra features in there at the moment.
Since this package is very in-line with wath I am doing and since it is far more mature, I'dd be willing to merge/donate them to this project.
Let me know if you are interested! We can always have a chat if you're up to it.
Add html component that contains functions to replace the following PHP builtin functions:
see https://github.com/nuxed/json
blocked by #42
All collection interfaces + Vector
and Map
class should be marked with @psalm-immutable
I understand that a completely reimplemented function in userland code will be slower than the compiled C counterpart, yet I thought that for many functions PSL simply implemented a wrapper for native functions, thus having little overhead.
I got a little surprised when I was replacing some instances of \array_unique
of suddenly getting a measurable drop in performance (those are rather large arrays, but that's what I get).
Here I can replicate it with this code:
$arr = [];
$iterations = 10;
$array_size = 1000;
$random_range = 5000;
for ($i = 0; $i < $array_size; $i++) {
$arr[] = Psl\SecureRandom\int(0, $random_range);
}
$total = 0;
$ta0 = microtime(true);
for ($e = 0; $e < $iterations; $e++) {
$total += \count(\array_unique($arr));
}
$ta1 = microtime(true);
echo "Native\n";
echo $total / $iterations, "\n";
echo 'Time: ' . round($ta1 - $ta0, 4), "\n\n";
$total = 0;
$ta0 = microtime(true);
for ($e = 0; $e < $iterations; $e++) {
$total += \Psl\Iter\count(\Psl\Dict\unique($arr));
}
$ta1 = microtime(true);
echo "Psl\n";
echo $total / $iterations, "\n";
echo 'Time: ' . round($ta1 - $ta0, 4);
The result in this case is 0.0009 seconds for native implementations, against 0.0841 seconds for using Psl. True, for this case 0,08 seconds is still something I can live with, but it's still a very marked cost increase. For my particular use case can even become problematic.
Is this what's expected, or I'm using the library incorrectly? Mind, this is not in no way a complaint, I love the library even if this is a tradeoff to be aware of, but just wanted to be sure this was not me "holding it wrong".
This bug was introduced in #169 by mistake, the solution would be to wrap all callbacks provided by the end user in another closure to ensure that strict types is used.
Environment (please complete the following information):
Additional context
Introduce a shell component containing a replacement for the following PHPs builtin shell functions:
Psl\Shell\escape_argument
)Psl\Shell\escape_command
)Psl\Shell\execute
)Psl\Shell\execute
must always return a string, containing the full output, if the command returned a non 0
exist code, an exception should be thrown.
The thrown exception should contain all information that the end user might need ( e.g: $exception->getCommand()
, $exception->getExitCode()
, $exception->getOutput()
.. etc )
Currently there is no type for specifying e.g. Type\list(Type\string())
.
Example use case:
$result = Json\typed($json, Type\vector(Type\string())->toArray();
Is your feature request related to a problem? Please describe.
Hi there,
This library is not install-able unless argon2 support has been compiled into php.
Otherwise, we will receive:
PHP Fatal error: Uncaught Error: Undefined constant 'PASSWORD_ARGON2I'
Describe the solution you'd like
Would you be open to conditionally supporting the argon2 password hashing, only if argon 2 support is available?
I want to use the iter/arr methods of this library - i don't really care about not having argon2 support.
Describe alternatives you've considered
compile in argon2 support before requiring psl.
All type function should be psalm-pure
All internal type clsses should be marked with psalm-immutable
since PSL 1.7 will require PHP 8.0, we should replace the usage of mixed
annotation with mixed
type hint.
see discussion in #53 ( #53 (comment) )
Questions:
We should probably have documentation that people can use to lookup functions and their descriptions + a couple of examples.
All functions within Psl\Iter
that return Generator
should be moved to Psl\Gen
.
A wrapper for Psl\Iter
should be created to return Psl\Iter\Iterator
instead of a generator ( i.e a rewindable, seekable iterator )
we should refactor all of our exceptions, and use error instead where it makes sense.
Exception
namespace to Throwable
namespace in all components.InvariantViolationException
( and rename to InvariantViolation
) - #308implement promises according to the Promises/A+ open standard.
Having contributors run php doc/documentor.php after every little change is annoying ( see #205 ), we should automate this via GitHub actions.
There are a lot of situations may occur when we need to define union from several cases.
For example: need to define enum of states.
This would look like:
use Psl\Type as T;
$codec = T\shape([
// ... rest of fields
'state' => T\union(
T\literal_scalar('NEW'),
T\union(
T\literal_scalar('APPROVED'),
T\union(
T\literal_scalar('REJECTED'),
T\union(
T\literal_scalar('COMPLETED'),
T\union(
T\literal_scalar('FROZEN'),
T\literal_scalar('ERROR')
)
)
)
)
),
]);
Inferred type would be:
array{id: string, state: "APPROVED"|"COMPLETED"|"ERROR"|"FROZEN"|"NEW"|"REJECTED"}
I guess it would be great to have better solution like:
use Psl\Type as T;
$codec = T\shape([
'id' => T\string(),
'state' => T\union_of(
T\literal_scalar('NEW'),
T\literal_scalar('APPROVED'),
T\literal_scalar('REJECTED'),
T\literal_scalar('COMPLETED'),
T\literal_scalar('FROZEN'),
T\literal_scalar('ERROR'),
),
]);
I do understand that Psl\Type\Internal\UnionType
has only 2 branches: left and right
That's why propose just implement a function with signature:
/**
* @template T
*
* @param TypeInterface<T> $left_type
* @param TypeInterface<T> $right_type
* @param TypeInterface<T> ...$others
* @return TypeInterface<T>
*
* @no-named-arguments
*/
function union_of(
TypeInterface $left_type,
TypeInterface $right_type,
TypeInterface ...$others
): TypeInterface { // actually Psl\Type\Internal\UnionType returns here
...
}
As alternatives I may guess there is more suitable name for function.
This may be named like literals
or one_of
or etc.
This function may also be implemented in user land, but I think it would be great to have unified solution inside core of the library.
Want to hear other guys thoughts.
If this would be approved, I may produce PR.
As I can see, this is very light enhancement.
Currently, it is not possible to convert a float -> string.
psl/src/Psl/Type/Internal/StringType.php
Line 39 in c34f75b
The other way around (string -> float) is possible.
We could go for one of these solutions to make it possible in a locale-safe way:
Would it make sense to add it and do you see any additional risks?
As Psl\
grows in size and adoption, its performance becomes one important evaluation point when considering it for downstream adoption.
This question came up in both #194 and Roave/BackwardCompatibilityCheck#306, and it would be a good idea to have reference/comparison.
The idea is to have following benchmarks:
For that, it would be interesting to use https://github.com/phpbench/phpbench/tree/1.0.1
@dantleech do you know if there is a sensible way to run benchmarks and compare them in CI? That's something that is kinda missing within PHPBench' docs 🤔
This is a meta issue to keep track of which QA tools are being used in PSL, the end goal is to have all these tools ( and more hopefully ) integrated with PSL and as part of our CI. ( PRs welcome! )
Tool | Description | Integrated |
---|---|---|
php-cs-fixer | PHP Coding Standards Fixer | ✅ |
php_codesniffer | ✔️ |
There's a lot of rules we have that are currently not enforced by CI:
Tool | Description | Integrated | Coverage |
---|---|---|---|
PSalm | Static Analysis tool. | ✅ | 100% |
PHPStan | Static Analysis tool. | ❌ | 0% |
SymfonyInsight | PHP project quality, done right. | ✅ | n/a |
php-assumptions | Tool to detect assumptions | ❌ | n/a? |
phpmd | ❌ | n/a? |
Tool | Description | Integrated | Coverage |
---|---|---|---|
PHPUnit | Unit Testing framework. | ✅ | 100% |
Tool | Description | Integrated |
---|---|---|
RoaveSecurityAdvisories | Security advisories as a simple composer exclusion list. | ✅ |
SymfonoySecurity | PHP security vulnerabilities monitoring. | ❌ |
Psalm ( taint analysis ) | Static Analysis tool. | ✅ |
The Obj
component should contain functions that are related to objects, or OOP in general.
examples ( not sure about the naming yet ):
Psl\Obj\contains_method($object, $method): bool
Psl\Obj\contains_property($object, $property): bool
Psl\Obj\class_exists($classname): bool
( always triggers the autoloader )pure Psl\Obj\class_included($classname): bool
( never triggers the autoloader )Migrate CI build from Travis-CI to GitHub actions.
Is your feature request related to a problem? Please describe.
When I try to read_file
which does not exist, is not file or is not readable InvariantViolationException
is thrown with message like $file does not exist
.
I would like to see given filename in exception message. It's than easier to debug and fix possible problem.
Describe the solution you'd like
Replace
Psl\invariant(exists($file), '$file does not exist.');
with
Psl\invariant(exists($file), Str\format('File "%s" does not exist.', $file));
Thrown RuntimeException
contains provided $file
too.
Just like Psl\Str\Byte
component, we want to add Psl\Str\Grapheme
that wraps grapheme_str* function in a nicer API that is consistent with our Psl\Str
and Psl\Str\Byte
components.
Is your feature request related to a problem? Please describe.
For some of our important projects, we need to use PHP 5.6 for comparability with the customers' environments.
Describe the solution you'd like
Any information on what it would take to use psl within a PHP 5.6 project.
Describe alternatives you've considered
Writing some of the functions we need ourselves over time. This library is much better.
Thank you to the creators and maintainers of psl.
Introduce a filesystem component containing a replacement for the following PHPs builtin filesystem functions:
Psl\Filesystem\basename
)Psl\Filesystem\chgrp
)Psl\Filesystem\chmod
)Psl\Filesystem\chown
)Psl\Filesystem\copy
)Psl\Filesystem\dirname
)Psl\Filesystem\file_exists
)Psl\Filesystem\glob
)Psl\Filesystem\is_dir
)Psl\Filesystem\is_executable
)Psl\Filesystem\is_file
)Psl\Filesystem\is_link
)Psl\Filesystem\is_readable
)Psl\Filesystem\is_writable
)Psl\Filesystem\link_chgrp
)Psl\Filesystem\link_chown
)Psl\Filesystem\link
)Psl\Filesystem\mkdir
)Psl\Filesystem\realpath
)Psl\Filesystem\rename
)Psl\Filesystem\rmdir
)Psl\Filesystem\symlink
)Psl\Filesystem\touch
)Psl\Filesystem\unlink
)add after{_ci|_last{_ci}}
and before{_ci|_last{_ci}}
helper string functions.
We should implement these functions for Psl\Str
, Psl\Str\Byte
, and Psl\Str\Grapheme
( refs #74 ), which totals to a new 24 functions.
Psl\Str
implementations would have an extra argument ?string $encoding = null
.
function after(string $haystack, string $needle, bool $include_needle = false, int $offset = 0): string;
function after_ci(string $haystack, string $needle, bool $include_needle = false, int $offset = 0): string;
function after_last(string $haystack, string $needle, bool $include_needle = false, int $offset = 0): string;
function after_last_ci(string $haystack, string $needle, bool $include_needle = false, int $offset = 0): string;
function before(string $haystack, string $needle, bool $include_needle = false, int $offset = 0): string;
function before_ci(string $haystack, string $needle, bool $include_needle = false, int $offset = 0): string;
function before_last(string $haystack, string $needle, bool $include_needle = false, int $offset = 0): string;
function before_last_ci(string $haystack, string $needle, bool $include_needle = false, int $offset = 0): string;
Dependabot can't resolve your PHP dependency files.
As a result, Dependabot couldn't update your dependencies.
The error Dependabot encountered was:
Your requirements could not be resolved to an installable set of packages.
Problem 1
- Root composer.json requires php-standard-library/psalm-plugin ^1.0 -> satisfiable by php-standard-library/psalm-plugin[1.0.0].
- php-standard-library/psalm-plugin 1.0.0 requires azjezz/psl ^1.5 -> satisfiable by azjezz/psl[1.5.0] from composer repo (https://repo.packagist.org) but azjezz/psl[1.0.0+no-version-set] from root package repo has higher repository priority. The packages with higher priority do not match your constraint and are therefore not installable. See https://getcomposer.org/repoprio for details and assistance.
If you think the above is an error on Dependabot's side please don't hesitate to get in touch - we'll do whatever we can to fix it.
wrap ext-intl
Dependabot can't resolve your PHP dependency files.
As a result, Dependabot couldn't update your dependencies.
The error Dependabot encountered was:
Your requirements could not be resolved to an installable set of packages.
Problem 1
- Root composer.json requires php-standard-library/psalm-plugin ^1.0 -> satisfiable by php-standard-library/psalm-plugin[1.0.0].
- php-standard-library/psalm-plugin 1.0.0 requires azjezz/psl ^1.5 -> satisfiable by azjezz/psl[1.5.0] from composer repo (https://repo.packagist.org) but azjezz/psl[1.0.0+no-version-set] from root package repo has higher repository priority. The packages with higher priority do not match your constraint and are therefore not installable. See https://getcomposer.org/repoprio for details and assistance.
If you think the above is an error on Dependabot's side please don't hesitate to get in touch - we'll do whatever we can to fix it.
I see that there is no array_sum()
equivalent provided.
Is this intentional, or is something that you'd be willing to consider?
Arr
and Iter
components are currently confusing, with some functions being pure, and other not, some returning lists, dicts, or just a value/key, or something else.
The idea would be:
Iter
would contain generic array functions that operate on all iterables, and usually don't return an iterable ( e.g: Iter\first, Iter\count, Iter\contains, Iter\contains_key .. etc )Vec
should contain every function that returns a vec ( i.e list ) from both Arr
and Iter
.Dict
should contain every function that returns a dict ( i.e array<Tk, Tv> ) from both Arr
and Iter
Arr
component ( all functions will be move to either Iter
, Vec
, or Dict
)This also means that we lazy loaded iterators, however, i don't see that as an issue, most functions will still accept iterables, so you can provide a generate, and wrap the result in a generator your self.
However, this doesn't solve the pure
issue, where functions are not considered pure, but after #119, we can extend the psalm plugin to make it so Vec\sort($array)
considered pure, while Vec\sort($db->getUsers())
( where $db->getUsers()
returns a mutable traversal ) considered impure.
Hi there!
Is your feature request related to a problem? Please describe.
Is is feasible to
non-empty-array
and non-empty-list
support to the type system, such that:Psl\Iter\first
and other functions can be T
and not T|null
?Describe the solution you'd like
I want to be able to do things like:
<?php
declare(strict_types=1);
use Psl;
class FooExtractor
{
/** @param list<Foo> $foos */
public function __invoke(array $foos): Foo
{
$foosFiltered = Vec\filter(
$foos,
function (Foo $foo): bool {
...
}
);
//assert $foosFiltered type is non-empty-list/array here.
//this will error as the return type is `T|null`
return Iter\first($foosFiltered);
}
}
Is there a better way to achieve what I'm trying to do?
Thanks!
Currently the Iter\reduce
function acts as a reduce_with_keys
. Is there a specific reason for this or is it safe to split it into reduce
, reduce_keys
and reduce_with_keys
function?
https://github.com/azjezz/psl/blob/develop/src/Psl/Iter/reduce.php
the Random
component currently implements cryptographically secure random functions, these should be moved to the SecureRandom
namespace, while adding pseudo-random functions under PseudoRandom
namespace.
i.e
function float(): float {
return (float)(namespace\int(0, Math\INT53_MAX - 1) / Math\INT53_MAX);
}
function int(int $min = Math\INT53_MIN, int $max = Math\INT53_MAX): int {
return mt_rand($min, $max);
}
In the context of following snippet:
/**
* @throws InvalidPackageName
*
* @psalm-pure
*/
public static function fromName(string $name): self
{
if (preg_match('{^[a-z0-9](?:[_.-]?[a-z0-9]+)*/[a-z0-9](?:(?:[_.]?|-{0,2})[a-z0-9]+)*$}iD', $name) !== 1) {
throw InvalidPackageName::fromInvalidName($name);
}
return new self(
non_empty_string()
->coerce($name)
);
}
psalm reports:
... Cannot call an impure function from a mutation-free context (see https://psalm.dev/202)
non_empty_string()
I wonder if all type constructors can/should be declared pure? Is this where we got stuck on conditional type purity?
Currently, tests are now being type-checked, but it would be nice if we do type check everything within PSL, tests included.
Add a new matches
method in internal types, and deprecate all Type\is_*($value)
functions in favor of Type\*()->matches($value)
.
psalm plugin should be moved to it's own repository ( https://github.com/php-standard-library/psalm-plugin )
TODO:
Psl\Psalm
( instead of Psl\Integration\Psl
)Describe the bug
Arr\flatten()
uses the index of the array to flatten it. This is ok for maps, but strange for lists:
To Reproduce
flatten([[1, 2, 3], [4, 5, 6]]);
Expected: [1, 2, 3, 4, 5, 6]
Actual: [4, 5, 6]
Additional context
Maybe we could make it behave more like the JS version for lists?
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.