项目作者: blyxxyz

项目描述 :
Import PHP code into Python
高级语言: Python
项目地址: git://github.com/blyxxyz/Python-PHP-Bridge.git
创建时间: 2018-04-23T05:20:48Z
项目社区:https://github.com/blyxxyz/Python-PHP-Bridge

开源协议:ISC License

下载


This is a Python module for running PHP programs. It lets you import PHP functions, classes, objects, constants and variables to work just like regular Python versions.

Examples

You can call functions:

  1. >>> from phpbridge import php
  2. >>> php.array_reverse(['foo', 'bar', 'baz'])
  3. Array.list(['baz', 'bar', 'foo'])
  4. >>> php.echo("foo\n")
  5. foo
  6. >>> php.getimagesize("http://php.net/images/logos/new-php-logo.png")
  7. Array([('0', 200), ('1', 106), ('2', 3), ('3', 'width="200" height="106"'), ('bits', 8), ('mime', 'image/png')])

You can create and use objects:

  1. >>> php.DateTime
  2. <PHP class 'DateTime'>
  3. >>> date = php.DateTime()
  4. >>> print(date)
  5. <DateTime PHP object (date='2018-05-03 22:59:15.114277', timezone_type=3, timezone='Europe/Berlin')>
  6. >>> date.getOffset()
  7. 7200
  8. >>> php.ArrayAccess
  9. <PHP interface 'ArrayAccess'>
  10. >>> issubclass(php.ArrayObject, php.ArrayAccess)
  11. True

You can use keyword arguments, even though PHP doesn’t support them:

  1. >>> date.setDate(year=1900, day=20, month=10)
  2. <DateTime PHP object (date='1900-10-20 22:59:15.114277', timezone_type=3, timezone='Europe/Berlin')>

You can loop over iterators and traversables:

  1. >>> for path, file in php.RecursiveIteratorIterator(php.RecursiveDirectoryIterator('.git/logs')):
  2. ... print("{}: {}".format(path, file.getSize()))
  3. ...
  4. .git/logs/.: 16
  5. .git/logs/..: 144
  6. .git/logs/HEAD: 2461
  7. [...]

You can get help:

  1. >>> help(php.echo)
  2. Help on function echo:
  3. echo(arg1, *rest)
  4. Output one or more strings.
  5. @param mixed $arg1
  6. @param mixed ...$rest
  7. @return void

You can import namespaces as modules:

  1. >>> from phpbridge.php.blyxxyz.PythonServer import NonFunctionProxy
  2. >>> help(NonFunctionProxy)
  3. Help on class blyxxyz\PythonServer\NonFunctionProxy in module phpbridge.php.blyxxyz.PythonServer:
  4. class blyxxyz\PythonServer\NonFunctionProxy(phpbridge.objects.PHPObject)
  5. | Provide function-like language constructs as static methods.
  6. |
  7. | `isset` and `empty` are not provided because it's impossible for a real
  8. | function to check whether its argument is defined.
  9. |
  10. | Method resolution order:
  11. | blyxxyz\PythonServer\NonFunctionProxy
  12. | phpbridge.objects.PHPObject
  13. | builtins.object
  14. |
  15. | Class methods defined here:
  16. |
  17. | array(val) -> dict from phpbridge.objects.PHPClass
  18. | Cast a value to an array.
  19. |
  20. | @param mixed $val
  21. |
  22. | @return array
  23. [...]

You can index, and get lengths:

  1. >>> arr = php.ArrayObject(['foo', 'bar', 'baz'])
  2. >>> arr[10] = 'foobar'
  3. >>> len(arr)
  4. 4

You can work with PHP’s exceptions:

  1. >>> try:
  2. ... php.get_resource_type(3)
  3. ... except php.TypeError as e:
  4. ... print(e.getMessage())
  5. ...
  6. get_resource_type() expects parameter 1 to be resource, integer given

Features

  • Using PHP functions
    • Keyword arguments are supported and translated based on the signature
    • Docblocks are also converted, so help is informative
  • Using PHP classes like Python classes
    • Methods and constants are defined right away based on the PHP class
    • Docblocks are treated like docstrings, so help works and is informative
    • The original inheritance structure is copied
    • Default properties become Python properties with documentation
    • Other properties are accessed on the fly as a fallback for attribute access
  • Creating and using objects
  • Importing namespaces as modules
  • Getting and setting constants
  • Getting and setting global variables
  • Translating exceptions so they can be treated as both Python exceptions and PHP objects
  • Tab completion in the interpreter
  • Python-like reprs for PHP objects, with information like var_dump in a more compact form

Caveats

  • On Windows, stdin and stderr are used to communicate, so PHP can’t read input and if it writes to stderr the connection is lost
  • You can only pass basic Python objects into PHP
  • Namespaces can shadow names in an unintuitive way
  • Because PHP only has one kind of array, its arrays are translated to a special kind of ordered dictionary

Name conflicts

Some PHP packages use the same name both for a class and a namespace. As an example, take nikic/PHP-Parser.

PhpParser\Node is a class, but PhpParser\Node\Param is also a class. This means phpbridge.php.PhpParser.Node becomes ambiguous - it could either refer to the Node class, or the namespace of the Param class.

In case of such a conflict, the class is preferred over the namespace. To get Param, a from import has to be used:

  1. >>> php.require('vendor/autoload.php')
  2. <Composer.Autoload.ClassLoader PHP object (prefixLengthsPsr4=[...: (4)], ...>
  3. >>> import phpbridge.php.PhpParser.Node as Node # Not the namespace!
  4. >>> Node
  5. <PHP interface 'PhpParser\Node'>
  6. >>> from phpbridge.php.PhpParser.Node import Param # The class we want
  7. >>> Param
  8. <PHP class 'PhpParser\Node\Param'>
  9. >>> import phpbridge.php.PhpParser.Node.Param as Param # Doesn't work
  10. Traceback (most recent call last):
  11. File "<stdin>", line 1, in <module>
  12. AttributeError: type object 'PhpParser\Node' has no attribute 'Param'

If there are no conflicts, things work as expected:

  1. >>> from phpbridge.php.blyxxyz.PythonServer import Commands
  2. >>> Commands
  3. <PHP class 'blyxxyz\PythonServer\Commands'>
  4. >>> import phpbridge.php.blyxxyz.PythonServer as PythonServer
  5. >>> PythonServer
  6. <PHP namespace 'blyxxyz\PythonServer'>
  7. >>> PythonServer.Commands
  8. <PHP class 'blyxxyz\PythonServer\Commands'>

Installing

  1. pip3 install phpbridge

The only dependencies are PHP 7.0+, Python 3.5+, ext-json, ext-reflection and ext-mbstring. Composer can be used to install development tools and set up autoloading, but it’s not required.