PHP模块,用于在InterSystems IRIS中使用分层数据

图片 自成立以来,PHP就因支持与许多库以及几乎所有市场上的DBMS集成而闻名(并受到批评)。 但是,由于一些奇怪的原因,它不支持全局变量上的分层数据库。

全局变量是用于存储分层信息的结构。 它们有点让人联想到“键->值”数据库,唯一的区别是键可以是多级的:

Set ^inn("1234567890", "city") = "Moscow" Set ^inn("1234567890", "city", "street") = "Req Square" Set ^inn("1234567890", "city", "street", "house") = 1 Set ^inn("1234567890", "year") = 1970 Set ^inn("1234567890", "name", "first") = "Vladimir" Set ^inn("1234567890", "name", "last") = "Ivanov" 

在此示例中,存储在硬盘上的全局^ inn中的内置ObjectScript语言(由全局名称前面的^图标指示)存储多级信息。

自然,要使用PHP的全局变量,我们需要PHP模块将添加的新功能,下面将对此进行讨论。

全局变量支持许多用于层次结构的功能:分别绕过每个级别的键,删除,复制和粘贴整个树和单个节点。 好吧,以及任何好的ACID交易数据库。 所有这一切都发生得非常快(在普通硬件上每秒大约执行10 5 -10 6插入操作),这有两个原因:

  1. 全局变量是比SQL低的抽象层次,
  2. 全球基地已有数十年的生产历史,在此期间,他们设法舔代码并对其进行了彻底的优化。

在“ Globals-数据存储的剑匠”系列文章中,有关globals的更多信息:

树木。 第一部分
树木。 第二部分
稀疏数组。 第三部分

在这个世界上,全球人已经在低结构性和稀疏信息的存储系统中找到了其主要应用,例如:医疗,个人数据,银行等。

我喜欢PHP(并在上面进行开发),并且想与Globals一起玩。 没有完成的模块。 我写信给InterSystems,要求我创建它。 等待没有任何结果,最后,我们(我和我的研究生)自己完成了该模块。 InterSystems赞助了这项开发,并将其作为教育补助金的一部分。

一般来说,InterSystems IRIS是一个多模型DBMS,因此从PHP您可以使用SQL通过ODBC使用它,但是我对全局变量感兴趣,并且没有这样的连接器。

因此,该模块可用于PHP 7.x(在7.0-7.2下测试)。 当前,它只能与安装在同一主机上的InterSystems IRIS和Caché一起使用。

OpenExchange上的“模块”页面 (InterSystems IRIS和Caché上开发人员的项目和附件目录)。

有一个有用的“讨论”部分,人们可以在其中共享使用经验。

在这里下载:
https://github.com/intersystems-community/php_ext_iris
从命令行下载存储库:

 git clone https://github.com/intersystems-community/php_ext_iris 

英文和俄文模块安装说明。

模块功能:
php功能内容描述
处理数据
iris_set($节点,值)
安装现场。
  1. iris_set($全局,$ subscript1,...,$ subscriptN,$ value);
    iris_set($全局,$值);

    返回: true或false(错误时)。
    所有函数参数都是字符串或数字。 第一个是全局名称,然后是索引,最后一个参数是值。

     iris_set('^time',1); iris_set('^time', 'tree', 1, 1, 'value'); 

    对象脚本上的模拟

     Set ^time = 1 Set ^time("tree", 1, 1) = "value" 
  2. iris_set($ arrayGlobal,$ value);
    仅2个参数:第一个是一个数组,其中存储了全局名称及其所有索引; 第二个是意思。

     $node = ['^time', 'tree', 1, 1]; iris_set($node,'value'); 

iris_get($节点)
读取节点。
返回:值(数字或字符串),NULL(未定义值)或FALSE(错误)。

  1. iris_get($全局,$ subscript1,...,$ subscriptN);
    iris_get($全球);
    所有函数参数都是字符串或数字。 第一个是全局名称,然后是索引。 全局可能没有索引。

     $res = iris_get('^time'); $res1 = iris_get('^time', 'tree', 1, 1); 
  2. iris_get($ arrayGlobal);
    唯一的参数是存储全局名称及其所有索引的数组。

     $node = ['^time', 'tree', 1, 1]; $res = iris_get($node); 

iris_zkill($节点)
删除节点值。
返回: TRUE或FALSE-错误。

重要的是要注意,此函数仅删除节点中的值,而不会涉及基础分支。

  1. iris_zkill($ global,$ subscript1,...,$ subscriptN);
    iris_zkill($全球);
    所有函数参数都是字符串或数字。 第一个是全局名称,然后是索引。 全局可能没有索引。

     $res = iris_zkill('^time'); //    . $res1 = iris_zkill('^time', 'tree', 1, 1); 
  2. iris_zkill($ arrayGlobal);
    唯一的参数是存储全局名称及其所有索引的数组。

     $a = ['^time', 'tree', 1, 1]; $res = iris_zkill($a); 

iris_kill($节点)
删除节点和所有后代分支。
返回:TRUE或FALSE-错误。

  1. iris_kill($ global,$ subscript1,...,$ subscriptN);
    iris_kill($全球);
    所有函数参数都是字符串或数字。 第一个是全局名称,然后是索引。 全局可能没有索引,在这种情况下,它会被完全删除。

     $res1 = iris_kill('^example', 'subscript1', 'subscript2'); $res = iris_kill('^time'); //   . 
  2. iris_kill($ arrayGlobal);
    唯一的参数是存储全局名称及其所有索引的数组。

     $a = ['^time', 'tree', 1, 1]; $res = iris_kill($a); 

iris_order($节点)
在给定级别绕过全局分支
返回:一个数组,其中包含下一个全局节点的全名或FALSE(发生错误)。

  1. iris_order($ global,$ subscript1,...,$ subscriptN);
    所有函数参数都是字符串或数字。 第一个是全局名称,然后是索引。

    PHP使用形式和ObjectScript等效:

     iris_order('^ccc','new2','res2'); // $Order(^ccc("new2", "res2")) 
  2. iris_order($ arrayGlobal);
    唯一的参数是存储起始节点的全局名称和索引的数组。

     $node = ['^inn', '1234567890', 'city']; for (; $node !== NULL; $node = iris_order($node)) { echo join(', ', $node).'='.iris_get($node)."\n"; } 

    将给我们一个结论:

     ^inn, 1234567890, city=Moscow ^inn, 1234567890, year=1970 

iris_order_rev($节点)
以给定的级别以相反的顺序绕过全局分支
返回:一个数组,该数组包含同一级别或FALSE的先前全局节点的全名(如果发生错误)。

  1. iris_order_rev($ global,$ subscript1,...,$ subscriptN);

    所有函数参数都是字符串或数字。 第一个是全局名称,然后是索引。

    PHP使用形式和ObjectScript等效:

     iris_order_rev('^ccc','new2','res2'); // $Order(^ccc("new2", "res2"), -1) 
  2. iris_order_rev($ arrayGlobal);

    唯一的参数是存储起始节点的全局名称和索引的数组。

     $node = ['^inn', '1234567890', 'name', 'last']; for (; $node !== NULL; $node = iris_order_rev($node)) { echo join(', ', $node).'='.iris_get($node)."\n"; } 

    将给我们一个结论:

     ^inn, 1234567890, name, last=Ivanov ^inn, 1234567890, name, first=Vladimir 

iris_query($ CmdLine)
通过进入较低级别绕过全球分支机构
返回:包含基础节点(如果有)或下一个全局节点(如果没有嵌套节点)全名数组。

  1. iris_query($ global,$ subscript1,...,$ subscriptN);
    所有函数参数都是字符串或数字。 第一个是全局名称,然后是索引。

    PHP使用形式和ObjectScript等效:

     iris_query('^ccc', 'new2', 'res2'); // $Query(^ccc("new2", "res2")) 
  2. iris_query($ arrayGlobal);
    唯一的参数是存储起始节点的全局名称和索引的数组。

     $node = ['^inn', 'city']; for (; $node !== NULL; $node = iris_query($node)) { echo join(', ', $node).'='.iris_get($node)."\n"; } 

    将给我们一个结论:

     ^inn, 1234567890, city=Moscow ^inn, 1234567890, city, street=Req Square ^inn, 1234567890, city, street, house=1 ^inn, 1234567890, name, first=Vladimir ^inn, 1234567890, name, last=Ivanov ^inn, 1234567890, year=1970 

该顺序不同于我们设置的顺序,因为在全局中,当您插入时自动将所有内容按升序排序。
服务功能
iris_set_dir($ FullPath)
设置数据库目录
返回: TRUE或FALSE-错误。

 iris_set_dir('/InterSystems/Cache/mgr'); 

必须先完成它,然后再连接数据库。
iris_exec($ CmdLine)
运行数据库命令
返回: TRUE或FALSE-错误。

 iris_exec('kill ^global(6)'); //   ObjectScript    

iris_connect($登录,$ pass)连接到数据库
iris_quit()断开与数据库的连接
iris_errno()获取错误代码
iris_error()获取错误的文本描述

如果您想自己玩这个模块,那么:

特别是对于Habr用户,创建了一个Dockerfile来构建映像。
 git clone https://github.com/intersystems-community/php_ext_iris cd php_ext_iris/iris docker-compose build docker-compose up -d 

在浏览器中的本地主机上测试演示页:52080

可以编辑和播放的PHP文件位于php / demo文件夹中,并将安装在容器内。

要测试IRIS,请使用用户名admin ,密码为SYS

要输入IRIS设置,请使用以下URL:
http://本地主机:52773 / csp / sys / UtilHome.csp

要输入此容器的IRIS控制台,请使用以下命令:
 docker exec -it iris_iris_1 iris session IRIS 


特别是对于Habr和InterSystemsCaché的用户,带有php-module的virtualka被取消。
俄语演示页。
英文演示页。
登录:habr_test
密码:burmur#@ 8765

用于在InterSystemsCaché下自动安装模块
  1. 有Linux。 我在Ubuntu下进行了测试,在Windows下也应该构建该模块,但是我没有对其进行测试。
  2. 下载免费版本:
  3. 根据说明,在PHP中安装cach.so模块。

在我的个人计算机(AMD FX-9370 @ 4700Mhz 32GB,LVM,SATA SSD)上的Docker容器中,为了娱乐,我对向数据库中插入新值的速度进行了两个原始测试。

  • 向全局插入一百万个新元素花费了1.81秒或每秒552K插入。
  • 在相同的全局1,000,000次中更新值花费1.98秒或每秒505K更新。 一个有趣的事实是插入比更新发生。 显然,这是为快速插入而进行的初始数据库优化的结果。

显然,这些测试不能说是准确和有用的,因为它们是在容器中进行的原始测试。 在具有PCIe SSD磁盘系统的更强大的硬件上,每秒可以实现数千万个插入。

可以完成的工作和当前状态


  1. 您可以添加有用的功能来处理事务(仍然可以通过iris_exec使用它们)。
  2. 返回全局的整个结构的功能未实现,因此PHP不会绕过全局。
  3. 未实现将PHP数组另存为子树的功能。
  4. 未实现对本地数据库变量的访问。 仅通过iris_exec,尽管通过iris_set更好。
  5. 没有实现绕过全局相反方向的深度。
  6. 未实现使用方法(类似于当前功能)通过对象访问数据库。

当前模块可能尚未准备好投入生产:没有针对高负载和内存泄漏的测试。 但是,如果有人需要,请与我联系(Sergey Kamenev updates@mail.ru)。

结论


长期以来,尽管全局变量在特定数据类型(医疗,个人)上提供了强大而快速的功能,但PHP的世界和基于全局变量的层次结构实际上并没有相交。

我希望该模块将成为PHP程序员与全球人员和ObjectScript程序员进行实验的动力,以简化PHP中的Web界面开发。

PS谢谢您的关注!

Source: https://habr.com/ru/post/zh-CN443440/


All Articles